@nudojs/core 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{check-report-TEOZ4cPZ.d.ts → check-report-BWmfy810.d.ts} +54 -2
- package/dist/{chunk-GD5XIQQK.js → chunk-5YNR4Q7E.js} +382 -130
- package/dist/{chunk-WB565PQK.js → chunk-CKH6GQAI.js} +3659 -2056
- package/dist/exec.d.ts +598 -3
- package/dist/exec.js +21 -1
- package/dist/index.d.ts +33 -31
- package/dist/index.js +351 -227
- package/dist/internal.d.ts +111 -7
- package/dist/internal.js +65 -3
- package/dist/{hof-types-COqDeD5F.d.ts → run-Dk08Q5zl.d.ts} +220 -2
- package/package.json +1 -1
- package/dist/index-DMjMPLV0.d.ts +0 -726
package/dist/index.js
CHANGED
|
@@ -9,12 +9,14 @@ import {
|
|
|
9
9
|
buildArgsFromAssume,
|
|
10
10
|
canSkipLiteralCallScan,
|
|
11
11
|
collectAbsFreeVars,
|
|
12
|
+
constraintAdmitsNullish,
|
|
12
13
|
constraintToEntryAbs,
|
|
13
14
|
effectiveInterface,
|
|
14
15
|
evictGeneralizeMemoForPaths,
|
|
15
16
|
execNudoModule,
|
|
16
17
|
extractDeclaredThrows,
|
|
17
18
|
extractFn,
|
|
19
|
+
extractFnBudget,
|
|
18
20
|
extractNudoImports,
|
|
19
21
|
extractRefineReturnFromSource,
|
|
20
22
|
extractRefinesFromSource,
|
|
@@ -30,6 +32,7 @@ import {
|
|
|
30
32
|
getTerm,
|
|
31
33
|
hashSource,
|
|
32
34
|
instantiateConstraint,
|
|
35
|
+
instantiateOnTerm,
|
|
33
36
|
interfaceDiagCount,
|
|
34
37
|
interfaceSourceOf,
|
|
35
38
|
interfaceTierOf,
|
|
@@ -44,6 +47,7 @@ import {
|
|
|
44
47
|
loadModuleDepsFingerprint,
|
|
45
48
|
localNamedExports,
|
|
46
49
|
normPath,
|
|
50
|
+
nullable,
|
|
47
51
|
number,
|
|
48
52
|
omit,
|
|
49
53
|
partial,
|
|
@@ -53,6 +57,7 @@ import {
|
|
|
53
57
|
resetGeneralizeMemo,
|
|
54
58
|
resetHashSourceCache,
|
|
55
59
|
resetNudoModuleExecCache,
|
|
60
|
+
resetSidecarLoadFailureCache,
|
|
56
61
|
scanLiteralCalls,
|
|
57
62
|
setInterfaceDiagCollector,
|
|
58
63
|
setRefineDiagCollector,
|
|
@@ -67,7 +72,7 @@ import {
|
|
|
67
72
|
takeRefineDiagsSince,
|
|
68
73
|
throwConstraintToKinds,
|
|
69
74
|
union
|
|
70
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-5YNR4Q7E.js";
|
|
71
76
|
import {
|
|
72
77
|
$add,
|
|
73
78
|
$arguments,
|
|
@@ -160,6 +165,7 @@ import {
|
|
|
160
165
|
$thisSet,
|
|
161
166
|
$throw,
|
|
162
167
|
$toNumber,
|
|
168
|
+
$toNumeric,
|
|
163
169
|
$tryCurrentMark,
|
|
164
170
|
$tryDetachSoftCatch,
|
|
165
171
|
$tryDigestSoftCatch,
|
|
@@ -172,6 +178,8 @@ import {
|
|
|
172
178
|
$tryTakeSince,
|
|
173
179
|
$typeof,
|
|
174
180
|
$unknown,
|
|
181
|
+
$updateAdd,
|
|
182
|
+
$updateSub,
|
|
175
183
|
$ushr,
|
|
176
184
|
$while,
|
|
177
185
|
$whileSeq,
|
|
@@ -186,6 +194,8 @@ import {
|
|
|
186
194
|
NudoThrow,
|
|
187
195
|
NudoUnsupportedError,
|
|
188
196
|
OBJECT_PROTO_METHOD_NAMES,
|
|
197
|
+
PROMISE_MICRO_ERROR_LABEL,
|
|
198
|
+
PROMISE_MICRO_OVERFLOW_LABEL,
|
|
189
199
|
RUNTIME_IMPORT_RE,
|
|
190
200
|
TYPEOF_NAMES,
|
|
191
201
|
abs,
|
|
@@ -203,10 +213,12 @@ import {
|
|
|
203
213
|
asAbs,
|
|
204
214
|
asAbsVal,
|
|
205
215
|
assignSourceSlots,
|
|
216
|
+
assumeFinite,
|
|
206
217
|
attachFnImpl,
|
|
207
218
|
beginCollectionFork,
|
|
208
219
|
betaOf,
|
|
209
220
|
bigintLit,
|
|
221
|
+
bindImports,
|
|
210
222
|
bindingsOf,
|
|
211
223
|
bitandAbs,
|
|
212
224
|
bitnotAbs,
|
|
@@ -225,6 +237,7 @@ import {
|
|
|
225
237
|
clearCollectionTables,
|
|
226
238
|
clearStaleTermPred,
|
|
227
239
|
cmp,
|
|
240
|
+
collectAbsExports,
|
|
228
241
|
collectionElementJoin,
|
|
229
242
|
collectionExactLen,
|
|
230
243
|
confJoin,
|
|
@@ -272,6 +285,7 @@ import {
|
|
|
272
285
|
foldRequireSpecArg,
|
|
273
286
|
foldStaticStringExpr,
|
|
274
287
|
formalParamDisplayNames,
|
|
288
|
+
formalParamSignatureNames,
|
|
275
289
|
formalParamsFromNodes,
|
|
276
290
|
formatAbs,
|
|
277
291
|
formatAbsMultiline,
|
|
@@ -292,6 +306,7 @@ import {
|
|
|
292
306
|
gt,
|
|
293
307
|
gtNum,
|
|
294
308
|
hostBuiltinCtorName,
|
|
309
|
+
identBoundaryRegex,
|
|
295
310
|
implies,
|
|
296
311
|
instantiateReturn,
|
|
297
312
|
isArrMutator,
|
|
@@ -354,6 +369,7 @@ import {
|
|
|
354
369
|
migrateNullProto,
|
|
355
370
|
mod,
|
|
356
371
|
mul,
|
|
372
|
+
namespaceAbsOf,
|
|
357
373
|
namespaceNameOf,
|
|
358
374
|
ne,
|
|
359
375
|
negAbs,
|
|
@@ -385,6 +401,7 @@ import {
|
|
|
385
401
|
primToTypeof,
|
|
386
402
|
projectFlatMapResult,
|
|
387
403
|
promoteParamShape,
|
|
404
|
+
propertyKeyOf,
|
|
388
405
|
protoBrandAbs,
|
|
389
406
|
protoOfRecv,
|
|
390
407
|
ptypeof,
|
|
@@ -434,6 +451,7 @@ import {
|
|
|
434
451
|
strLit,
|
|
435
452
|
strictEqAbs,
|
|
436
453
|
stringOfSymbol,
|
|
454
|
+
stripStringsKeepComments,
|
|
437
455
|
stripTypes,
|
|
438
456
|
sub,
|
|
439
457
|
substAbs,
|
|
@@ -466,7 +484,7 @@ import {
|
|
|
466
484
|
v,
|
|
467
485
|
withExecPhi,
|
|
468
486
|
withVar
|
|
469
|
-
} from "./chunk-
|
|
487
|
+
} from "./chunk-CKH6GQAI.js";
|
|
470
488
|
|
|
471
489
|
// src/environment.ts
|
|
472
490
|
function createEnvironment(parent, bindings = /* @__PURE__ */ new Map()) {
|
|
@@ -699,6 +717,252 @@ function formatDiagnostics(diags) {
|
|
|
699
717
|
}).join("\n");
|
|
700
718
|
}
|
|
701
719
|
|
|
720
|
+
// src/algebra/postcondition.ts
|
|
721
|
+
function proved() {
|
|
722
|
+
return { status: "proved" };
|
|
723
|
+
}
|
|
724
|
+
function disproved(reason) {
|
|
725
|
+
return { status: "disproved", reason };
|
|
726
|
+
}
|
|
727
|
+
function unprovable(reason) {
|
|
728
|
+
return { status: "unprovable", reason };
|
|
729
|
+
}
|
|
730
|
+
var RET_ANCHOR = "__nudo_return__";
|
|
731
|
+
function retAnchorTerm(ret) {
|
|
732
|
+
return ret.term ?? v(RET_ANCHOR);
|
|
733
|
+
}
|
|
734
|
+
function isValueSetUnknown(ret) {
|
|
735
|
+
if (ret.conf === "opaque" || ret.conf === "widened" || ret.conf === "mock") {
|
|
736
|
+
return true;
|
|
737
|
+
}
|
|
738
|
+
if (ret.shape.k === "unknown" && !ret.term) return true;
|
|
739
|
+
if (ret.shape.k === "any") return true;
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
function isBoundedEvidenceMissing(ret, constraint) {
|
|
743
|
+
if (constraint.preds.length === 0 && !constraint.members) return false;
|
|
744
|
+
if (ret.term?.op === "lit") return false;
|
|
745
|
+
if (ret.pred && ret.pred.op !== "true") return false;
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
function assertImplies(ret, constraint, opts) {
|
|
749
|
+
const phi = opts?.phi ?? pTrue;
|
|
750
|
+
if (ret.shape.k === "never") return proved();
|
|
751
|
+
if (isAnyConstraint(constraint)) return proved();
|
|
752
|
+
const nullishOk = constraintAdmitsNullish(constraint);
|
|
753
|
+
if (isNullishLitAbs(ret)) {
|
|
754
|
+
return nullishOk ? proved() : disproved(`nullish return \u22AD ${formatConstraint(constraint)}`);
|
|
755
|
+
}
|
|
756
|
+
let sumMembers;
|
|
757
|
+
if (ret.shape.k === "sum") {
|
|
758
|
+
const members = ret.shape.members;
|
|
759
|
+
const nullishMembers = members.filter((m) => isNullishLitAbs(m));
|
|
760
|
+
if (nullishMembers.length > 0 && !nullishOk) {
|
|
761
|
+
return disproved(
|
|
762
|
+
`nullish return arm \u22AD ${formatConstraint(constraint)} (contract does not admit nullish)`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
sumMembers = members.filter((m) => !isNullishLitAbs(m));
|
|
766
|
+
}
|
|
767
|
+
if (isValueSetUnknown(ret)) {
|
|
768
|
+
return unprovable(
|
|
769
|
+
ret.shape.k === "any" ? "any does not establish the return contract" : "inference failure (unknown/opaque) \u2014 cannot prove the return contract"
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
if (constraint.members && constraint.members.length > 0) {
|
|
773
|
+
let sawUnprovable = false;
|
|
774
|
+
for (const m of constraint.members) {
|
|
775
|
+
const r = assertImplies(ret, m, opts);
|
|
776
|
+
if (r.status === "proved") return proved();
|
|
777
|
+
if (r.status === "unprovable") sawUnprovable = true;
|
|
778
|
+
}
|
|
779
|
+
return sawUnprovable ? unprovable("union: no member proved the return contract") : disproved(`return \u22AD union(${constraint.members.map((m) => formatConstraint(m)).join(", ")})`);
|
|
780
|
+
}
|
|
781
|
+
if (sumMembers && constraint.fields) {
|
|
782
|
+
let sawUnprovable = false;
|
|
783
|
+
for (const m of sumMembers) {
|
|
784
|
+
if (isValueSetUnknown(m)) continue;
|
|
785
|
+
const r = assertImplies(m, constraint, opts);
|
|
786
|
+
if (r.status === "disproved") return r;
|
|
787
|
+
if (r.status === "unprovable") sawUnprovable = true;
|
|
788
|
+
}
|
|
789
|
+
return sawUnprovable ? unprovable("sum: some arms unprovable") : proved();
|
|
790
|
+
}
|
|
791
|
+
if (constraint.fields) {
|
|
792
|
+
return assertShapeFields(ret, constraint, opts);
|
|
793
|
+
}
|
|
794
|
+
if (constraint.element) {
|
|
795
|
+
if (ret.shape.k !== "arr" && ret.shape.k !== "tuple") {
|
|
796
|
+
return disproved(`return shape ${ret.shape.k} \u22AD array(...)`);
|
|
797
|
+
}
|
|
798
|
+
return proved();
|
|
799
|
+
}
|
|
800
|
+
if (constraint.fn) return proved();
|
|
801
|
+
return assertScalar(ret, constraint, phi);
|
|
802
|
+
}
|
|
803
|
+
function isAnyConstraint(c) {
|
|
804
|
+
return !c.prim && c.preds.length === 0 && !c.fields && !c.element && !c.members && !c.fn && !isIntFlag(c);
|
|
805
|
+
}
|
|
806
|
+
function assertShapeFields(ret, constraint, opts) {
|
|
807
|
+
let slots;
|
|
808
|
+
if (ret.shape.k === "obj") {
|
|
809
|
+
slots = ret.shape.slots;
|
|
810
|
+
} else if (ret.shape.k === "brand") {
|
|
811
|
+
const inner = ret.shape.shape;
|
|
812
|
+
if (inner.shape.k === "obj") slots = inner.shape.slots;
|
|
813
|
+
}
|
|
814
|
+
if (!slots) {
|
|
815
|
+
return disproved(`return shape ${ret.shape.k} \u22AD object shape`);
|
|
816
|
+
}
|
|
817
|
+
for (const [key, field] of Object.entries(constraint.fields)) {
|
|
818
|
+
const slot = getSlot(slots, key);
|
|
819
|
+
if (!slot) {
|
|
820
|
+
if (!field.optional && !field.constraint.isOptional) {
|
|
821
|
+
return disproved(`missing field ${key}`);
|
|
822
|
+
}
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
const r = assertImplies(slot.value, field.constraint, opts);
|
|
826
|
+
if (r.status === "disproved") {
|
|
827
|
+
return disproved(`field ${key}: ${r.reason}`);
|
|
828
|
+
}
|
|
829
|
+
if (r.status === "unprovable") {
|
|
830
|
+
return unprovable(`field ${key}: ${r.reason}`);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
return proved();
|
|
834
|
+
}
|
|
835
|
+
function assertScalar(ret, constraint, phi) {
|
|
836
|
+
if (constraint.prim) {
|
|
837
|
+
const retPrim = primOfAbs(ret);
|
|
838
|
+
if (retPrim && retPrim !== constraint.prim) {
|
|
839
|
+
return disproved(`typeof return = "${retPrim}" \u22AD "${constraint.prim}"`);
|
|
840
|
+
}
|
|
841
|
+
if (!retPrim && ret.shape.k !== "sum" && ret.shape.k !== "never") {
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (isIntFlag(constraint) && constraint.prim === "number") {
|
|
845
|
+
const lv2 = litValue(ret);
|
|
846
|
+
if (typeof lv2 === "number" && !Number.isInteger(lv2)) {
|
|
847
|
+
return disproved(`return ${lv2} \u22AD int`);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const t = retAnchorTerm(ret);
|
|
851
|
+
const constraintPred = instantiateOnTerm(constraint, t);
|
|
852
|
+
const retPred = ret.pred && ret.pred.op !== "true" ? phi.op === "true" ? ret.pred : and(phi, ret.pred) : phi;
|
|
853
|
+
if (constraint.preds.length === 0 && constraintPred.op === "true") {
|
|
854
|
+
return proved();
|
|
855
|
+
}
|
|
856
|
+
if (constraint.preds.length === 0 && constraintPred.op === "typeof" && constraint.prim) {
|
|
857
|
+
return proved();
|
|
858
|
+
}
|
|
859
|
+
if (constraintPred.op !== "true") {
|
|
860
|
+
if (implies(retPred, constraintPred)) return proved();
|
|
861
|
+
if (ret.pred && ret.pred.op !== "true" && numericBoundsImplyLocal(ret.pred, constraintPred)) {
|
|
862
|
+
return proved();
|
|
863
|
+
}
|
|
864
|
+
if (isBoundedEvidenceMissing(ret, constraint)) {
|
|
865
|
+
return unprovable(
|
|
866
|
+
`cannot prove return satisfies ${formatConstraint(constraint)} (no bound evidence on the return value)`
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
const lv = litValue(ret);
|
|
871
|
+
if (lv !== void 0 && (typeof lv === "number" || typeof lv === "string" || typeof lv === "boolean" || lv === null)) {
|
|
872
|
+
if (literalMeetsConstraint(lv, constraint)) {
|
|
873
|
+
return proved();
|
|
874
|
+
}
|
|
875
|
+
const boundDesc = describeBoundViolation(lv, constraint);
|
|
876
|
+
return disproved(
|
|
877
|
+
boundDesc ?? `return ${JSON.stringify(lv)} \u22AD ${formatConstraint(constraint)}`
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
if (ret.term?.op === "lit" && ret.term.value === void 0) {
|
|
881
|
+
return proved();
|
|
882
|
+
}
|
|
883
|
+
if (constraintPred.op !== "true" || constraint.preds.length > 0) {
|
|
884
|
+
if (isBoundedEvidenceMissing(ret, constraint)) {
|
|
885
|
+
return unprovable(
|
|
886
|
+
`cannot prove return satisfies ${formatConstraint(constraint)} (no bound evidence on the return value)`
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
return disproved(
|
|
890
|
+
`return (${formatAbs(ret)}) \u22AD ${formatConstraint(constraint)} (postcondition not implied)`
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
return proved();
|
|
894
|
+
}
|
|
895
|
+
function numericBoundsImplyLocal(src, tgt) {
|
|
896
|
+
const one = (p) => p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le";
|
|
897
|
+
if (!one(src) || !one(tgt)) return false;
|
|
898
|
+
if (src.op !== tgt.op) {
|
|
899
|
+
if (src.op === "gt" && tgt.op === "ge") {
|
|
900
|
+
return sameTermSide(src, tgt) && litGE(src.b, tgt.b);
|
|
901
|
+
}
|
|
902
|
+
if (src.op === "lt" && tgt.op === "le") {
|
|
903
|
+
return sameTermSide(src, tgt) && litLE(src.b, tgt.b);
|
|
904
|
+
}
|
|
905
|
+
return false;
|
|
906
|
+
}
|
|
907
|
+
if (!sameTermSide(src, tgt)) return false;
|
|
908
|
+
const sb = src.b.op === "lit" ? src.b.value : void 0;
|
|
909
|
+
const tb = tgt.b.op === "lit" ? tgt.b.value : void 0;
|
|
910
|
+
if (typeof sb !== "number" || typeof tb !== "number") return false;
|
|
911
|
+
if (src.op === "gt" || src.op === "ge") return sb >= tb;
|
|
912
|
+
return sb <= tb;
|
|
913
|
+
}
|
|
914
|
+
function sameTermSide(a, b) {
|
|
915
|
+
return a.a.op === b.a.op && termEquals(a.a, b.a);
|
|
916
|
+
}
|
|
917
|
+
function litGE(a, b) {
|
|
918
|
+
if (a.op !== "lit" || b.op !== "lit") return false;
|
|
919
|
+
return typeof a.value === "number" && typeof b.value === "number" && a.value >= b.value;
|
|
920
|
+
}
|
|
921
|
+
function litLE(a, b) {
|
|
922
|
+
if (a.op !== "lit" || b.op !== "lit") return false;
|
|
923
|
+
return typeof a.value === "number" && typeof b.value === "number" && a.value <= b.value;
|
|
924
|
+
}
|
|
925
|
+
function primOfAbs(a) {
|
|
926
|
+
if (a.shape.k === "prim") return a.shape.type;
|
|
927
|
+
const lv = litValue(a);
|
|
928
|
+
if (typeof lv === "number") return "number";
|
|
929
|
+
if (typeof lv === "string") return "string";
|
|
930
|
+
if (typeof lv === "boolean") return "boolean";
|
|
931
|
+
if (typeof lv === "bigint") return "bigint";
|
|
932
|
+
return void 0;
|
|
933
|
+
}
|
|
934
|
+
function describeBoundViolation(lv, constraint) {
|
|
935
|
+
const opSym = { gt: ">", ge: "\u2265", lt: "<", le: "\u2264" };
|
|
936
|
+
for (const p of constraint.preds) {
|
|
937
|
+
for (const atom of p.op === "and" ? p.args : [p]) {
|
|
938
|
+
if (atom.op !== "gt" && atom.op !== "ge" && atom.op !== "lt" && atom.op !== "le") continue;
|
|
939
|
+
if (atom.b.op !== "lit" || typeof atom.b.value !== "number") continue;
|
|
940
|
+
const n = atom.b.value;
|
|
941
|
+
const sym = opSym[atom.op];
|
|
942
|
+
if (typeof lv === "number") {
|
|
943
|
+
let ok = true;
|
|
944
|
+
if (atom.op === "gt") ok = lv > n;
|
|
945
|
+
if (atom.op === "ge") ok = lv >= n;
|
|
946
|
+
if (atom.op === "lt") ok = lv < n;
|
|
947
|
+
if (atom.op === "le") ok = lv <= n;
|
|
948
|
+
if (!ok) return `return ${sym} ${n}`;
|
|
949
|
+
}
|
|
950
|
+
if (typeof lv === "string" && isLengthSelfTerm(atom.a)) {
|
|
951
|
+
let ok = true;
|
|
952
|
+
if (atom.op === "gt") ok = lv.length > n;
|
|
953
|
+
if (atom.op === "ge") ok = lv.length >= n;
|
|
954
|
+
if (atom.op === "lt") ok = lv.length < n;
|
|
955
|
+
if (atom.op === "le") ok = lv.length <= n;
|
|
956
|
+
if (!ok) return `length(self) ${sym} ${n}`;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return void 0;
|
|
961
|
+
}
|
|
962
|
+
function isLengthSelfTerm(t) {
|
|
963
|
+
return t.op === "app" && t.fn === "length" && t.args.length === 1 && t.args[0].op === "var" && t.args[0].id === SELF;
|
|
964
|
+
}
|
|
965
|
+
|
|
702
966
|
// src/algebra/projection.ts
|
|
703
967
|
var PROJECTABLE_CONF = /* @__PURE__ */ new Set(["exact", "path"]);
|
|
704
968
|
var ARR_FALLBACK_CONF = /* @__PURE__ */ new Set([
|
|
@@ -1133,8 +1397,9 @@ function estimateEntryParamCount(source, fnName, file) {
|
|
|
1133
1397
|
}
|
|
1134
1398
|
} catch {
|
|
1135
1399
|
}
|
|
1400
|
+
const name = identBoundaryRegex(fnName);
|
|
1136
1401
|
const re = new RegExp(
|
|
1137
|
-
`(?:function\\s+${
|
|
1402
|
+
`(?:function\\s+${name}\\s*\\(([^)]*)\\)|${name}\\s*=\\s*(?:async\\s*)?function(?:\\s+${name})?\\s*\\(([^)]*)\\)|${name}\\s*=\\s*(?:async\\s*)?\\(([^)]*)\\)\\s*=>)`
|
|
1138
1403
|
);
|
|
1139
1404
|
const m = re.exec(source);
|
|
1140
1405
|
if (m) {
|
|
@@ -1145,13 +1410,15 @@ function estimateEntryParamCount(source, fnName, file) {
|
|
|
1145
1410
|
return 1;
|
|
1146
1411
|
}
|
|
1147
1412
|
function isDefaultExportName(source, fnName) {
|
|
1413
|
+
const name = identBoundaryRegex(fnName);
|
|
1148
1414
|
const re = new RegExp(
|
|
1149
|
-
`export\\s+default\\s+(?:async\\s+)?(?:function\\s+${
|
|
1415
|
+
`export\\s+default\\s+(?:async\\s+)?(?:function\\s+${name}|${name})`
|
|
1150
1416
|
);
|
|
1151
1417
|
return re.test(source);
|
|
1152
1418
|
}
|
|
1153
1419
|
function formatEntrySigLine(name, g, throws) {
|
|
1154
|
-
const
|
|
1420
|
+
const names = g.formals && g.formals.length > 0 ? formalParamSignatureNames(g.formals) : g.params;
|
|
1421
|
+
const ps = names.map((p, i) => {
|
|
1155
1422
|
const t = g.typeParams[i]?.value;
|
|
1156
1423
|
const shown = !t ? "any" : t.shape.k === "unknown" ? "unknown" : formatShape(t);
|
|
1157
1424
|
return `${p}: ${shown}`;
|
|
@@ -1215,6 +1482,7 @@ function resetCheckSourceMemo() {
|
|
|
1215
1482
|
checkKeyDeps.clear();
|
|
1216
1483
|
checkDepIndex.clear();
|
|
1217
1484
|
resetHashSourceCache();
|
|
1485
|
+
resetSidecarLoadFailureCache();
|
|
1218
1486
|
}
|
|
1219
1487
|
function loadModuleId(fn2) {
|
|
1220
1488
|
if (!fn2) return 0;
|
|
@@ -1465,8 +1733,11 @@ function widenForAssign(a) {
|
|
|
1465
1733
|
a.conf
|
|
1466
1734
|
);
|
|
1467
1735
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1736
|
+
if (a.term?.op === "lit") {
|
|
1737
|
+
const lv = a.term.value;
|
|
1738
|
+
if (lv === null || lv === void 0) {
|
|
1739
|
+
return abs({ k: "unknown" }, void 0, void 0, a.conf);
|
|
1740
|
+
}
|
|
1470
1741
|
if (typeof lv === "number") {
|
|
1471
1742
|
return abs({ k: "prim", type: "number" }, void 0, void 0, a.conf);
|
|
1472
1743
|
}
|
|
@@ -1518,8 +1789,9 @@ function projectCaseArgField(arg, field) {
|
|
|
1518
1789
|
}
|
|
1519
1790
|
function scanCaseInconsistency(source, knownFns, opts) {
|
|
1520
1791
|
const out = [];
|
|
1521
|
-
|
|
1522
|
-
|
|
1792
|
+
const directiveSrc = stripStringsKeepComments(source);
|
|
1793
|
+
if (!directiveSrc.includes("@nudo:case")) return out;
|
|
1794
|
+
const hasContractOrigin = directiveSrc.includes("@nudo:contract") || opts.sidecarPresent === true;
|
|
1523
1795
|
if (!hasContractOrigin) return out;
|
|
1524
1796
|
const file = opts.file ?? parseSource(source);
|
|
1525
1797
|
const parseLitArg = (s) => {
|
|
@@ -1742,6 +2014,7 @@ function checkSource(filePath, source, phi = pTrue, opts = {}) {
|
|
|
1742
2014
|
}
|
|
1743
2015
|
setRefineDiagCollector(null);
|
|
1744
2016
|
setInterfaceDiagCollector(null);
|
|
2017
|
+
resetSidecarLoadFailureCache();
|
|
1745
2018
|
const refineSince = refineDiagCount();
|
|
1746
2019
|
const ifaceSince = interfaceDiagCount();
|
|
1747
2020
|
const useMemo = phi.op === "true";
|
|
@@ -1817,7 +2090,7 @@ function sidecarDiagIssues(diags) {
|
|
|
1817
2090
|
return out;
|
|
1818
2091
|
}
|
|
1819
2092
|
function checkSourceInner(filePath, source, file, phi, opts, issues, signatures, names, truncated, identityOpts = opts, depsFp, sidecarFp) {
|
|
1820
|
-
const hasRefineDirective = source
|
|
2093
|
+
const hasRefineDirective = stripStringsKeepComments(source).includes("@nudo:contract");
|
|
1821
2094
|
const exportedNames = sidecarFp !== void 0 ? localNamedExports(source) : void 0;
|
|
1822
2095
|
const entryNames = localNamedExports(source);
|
|
1823
2096
|
const entryThrowsMode = opts.entryThrows ?? "error";
|
|
@@ -1882,7 +2155,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
1882
2155
|
eff.returns.constraint,
|
|
1883
2156
|
declared
|
|
1884
2157
|
);
|
|
1885
|
-
if (retIssues.
|
|
2158
|
+
if (retIssues.some((i) => i.severity === "error")) returnViolated.add(name);
|
|
1886
2159
|
issues.push(...retIssues);
|
|
1887
2160
|
}
|
|
1888
2161
|
continue;
|
|
@@ -1928,7 +2201,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
1928
2201
|
message: `${name} (export): may throw ${gateDisplay}`,
|
|
1929
2202
|
actual: `${name}(\u2026) throws ${gateDisplay}`,
|
|
1930
2203
|
expected: "entry total, or @nudo:throws / try-catch",
|
|
1931
|
-
suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / refine / guard / try-catch`,
|
|
2204
|
+
suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`,
|
|
1932
2205
|
fn: name,
|
|
1933
2206
|
...loc.line !== void 0 ? { line: loc.line } : {},
|
|
1934
2207
|
...loc.column !== void 0 ? { column: loc.column } : {}
|
|
@@ -1973,7 +2246,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
1973
2246
|
message: `${name} (export): may throw ${gateDisplay}`,
|
|
1974
2247
|
actual: `${formatEntrySigLine(name, g, gateDisplay)}`,
|
|
1975
2248
|
expected: "entry total, or @nudo:throws / try-catch",
|
|
1976
|
-
suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / refine / guard / try-catch`,
|
|
2249
|
+
suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`,
|
|
1977
2250
|
fn: name,
|
|
1978
2251
|
...loc.line !== void 0 ? { line: loc.line } : {},
|
|
1979
2252
|
...loc.column !== void 0 ? { column: loc.column } : {}
|
|
@@ -1991,7 +2264,8 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
1991
2264
|
});
|
|
1992
2265
|
signatures.push({
|
|
1993
2266
|
name,
|
|
1994
|
-
|
|
2267
|
+
// 解构形参展示 `{ grade, findings }`,不落 `_p0`(#64:契约要上屏)
|
|
2268
|
+
params: g.formals && g.formals.length > 0 ? formalParamSignatureNames(g.formals) : g.params,
|
|
1995
2269
|
paramTypes,
|
|
1996
2270
|
abs: g.symbolic,
|
|
1997
2271
|
display: throwsDisplay ? `${fmt.display} throws ${throwsDisplay}` : fmt.display,
|
|
@@ -2071,7 +2345,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2071
2345
|
eff.returns.constraint,
|
|
2072
2346
|
g.symbolic
|
|
2073
2347
|
);
|
|
2074
|
-
if (retIssues.
|
|
2348
|
+
if (retIssues.some((i) => i.severity === "error")) returnViolated.add(name);
|
|
2075
2349
|
issues.push(...retIssues);
|
|
2076
2350
|
}
|
|
2077
2351
|
if (eff && eff.source === "generated") {
|
|
@@ -2098,7 +2372,25 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2098
2372
|
severity: "info",
|
|
2099
2373
|
code: "nudo:fork-truncated",
|
|
2100
2374
|
message: `Branch expansion was truncated (fork budget); affected results widened to unknown#opaque (budget)`,
|
|
2101
|
-
suggestion: "optional:
|
|
2375
|
+
suggestion: "optional: raise nudo.analysis.maxForks, or @nudo:budget forks=\u2026 on the function \u2014 non-blocking"
|
|
2376
|
+
});
|
|
2377
|
+
continue;
|
|
2378
|
+
}
|
|
2379
|
+
if (label === PROMISE_MICRO_OVERFLOW_LABEL) {
|
|
2380
|
+
issues.push({
|
|
2381
|
+
severity: "info",
|
|
2382
|
+
code: "nudo:promise-micro-truncated",
|
|
2383
|
+
message: `Promise microtask queue hit its hard cap; further then/catch callbacks were dropped (results stay fail-closed)`,
|
|
2384
|
+
suggestion: "optional: reduce top-level Promise.then fan-out \u2014 non-blocking"
|
|
2385
|
+
});
|
|
2386
|
+
continue;
|
|
2387
|
+
}
|
|
2388
|
+
if (label === PROMISE_MICRO_ERROR_LABEL) {
|
|
2389
|
+
issues.push({
|
|
2390
|
+
severity: "info",
|
|
2391
|
+
code: "nudo:promise-micro-error",
|
|
2392
|
+
message: `A promise microtask threw while draining; the error was recorded and did not rewrite the synchronous return value`,
|
|
2393
|
+
suggestion: "optional: inspect the then/catch callback for a throw path \u2014 non-blocking"
|
|
2102
2394
|
});
|
|
2103
2395
|
continue;
|
|
2104
2396
|
}
|
|
@@ -2117,7 +2409,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2117
2409
|
severity: "info",
|
|
2118
2410
|
code: "nudo:recursion-truncated",
|
|
2119
2411
|
message: `Recursive evaluation of '${label}' was truncated (depth/size budget); result widened to unknown#opaque (budget \u2014 not inference debt)`,
|
|
2120
|
-
suggestion: "narrow the recursion base case
|
|
2412
|
+
suggestion: "raise the function budget with @nudo:budget calls=\u2026 depth=\u2026 (or narrow the recursion base case / declare @nudo:contract return)",
|
|
2121
2413
|
fn: label
|
|
2122
2414
|
});
|
|
2123
2415
|
}
|
|
@@ -2180,7 +2472,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2180
2472
|
rc.constraint,
|
|
2181
2473
|
rec.result
|
|
2182
2474
|
);
|
|
2183
|
-
if (retIssues.
|
|
2475
|
+
if (retIssues.some((i) => i.severity === "error")) returnViolated.add(rec.fnName);
|
|
2184
2476
|
issues.push(...retIssues);
|
|
2185
2477
|
}
|
|
2186
2478
|
}
|
|
@@ -2239,118 +2531,33 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2239
2531
|
};
|
|
2240
2532
|
}
|
|
2241
2533
|
function checkReturnConstraint(fnName, cName, constraint, ret) {
|
|
2242
|
-
const
|
|
2243
|
-
if (
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
for (const m of ret.shape.members) {
|
|
2249
|
-
for (const issue of checkReturnConstraint(fnName, cName, constraint, m)) {
|
|
2250
|
-
const key = `${issue.message}\0${issue.actual ?? ""}\0${issue.expected ?? ""}`;
|
|
2251
|
-
if (seen.has(key)) continue;
|
|
2252
|
-
seen.add(key);
|
|
2253
|
-
out.push(issue);
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
return out;
|
|
2257
|
-
}
|
|
2258
|
-
const push = (actual, expected, suggestion) => {
|
|
2259
|
-
out.push({
|
|
2260
|
-
severity: "error",
|
|
2261
|
-
code: "nudo:constraint-violated",
|
|
2534
|
+
const proof = assertImplies(ret, constraint);
|
|
2535
|
+
if (proof.status === "proved") return [];
|
|
2536
|
+
const push = (severity, actual, expected, suggestion) => [
|
|
2537
|
+
{
|
|
2538
|
+
severity,
|
|
2539
|
+
code: severity === "error" ? "nudo:constraint-violated" : "nudo:unproven-return",
|
|
2262
2540
|
message: `${fnName}: return value \u22AD @nudo:contract return ${cName}`,
|
|
2263
2541
|
actual,
|
|
2264
2542
|
expected,
|
|
2265
2543
|
suggestion,
|
|
2266
2544
|
fn: fnName
|
|
2267
|
-
});
|
|
2268
|
-
};
|
|
2269
|
-
if (constraint.fields) {
|
|
2270
|
-
const slots = ret.shape.k === "obj" ? ret.shape.slots : void 0;
|
|
2271
|
-
if (!slots) {
|
|
2272
|
-
if (ret.shape.k !== "never") {
|
|
2273
|
-
push(formatAbs(ret), `object shape (${cName})`, `return an object satisfying the ${cName} shape`);
|
|
2274
|
-
}
|
|
2275
|
-
return out;
|
|
2276
|
-
}
|
|
2277
|
-
for (const [key, field] of Object.entries(constraint.fields)) {
|
|
2278
|
-
const slot = getSlot(slots, key);
|
|
2279
|
-
if (!slot) {
|
|
2280
|
-
if (!field.optional && !field.constraint.isOptional) {
|
|
2281
|
-
push(formatAbs(ret), `missing field ${key}`, `add the missing field ${key} to the return value`);
|
|
2282
|
-
}
|
|
2283
|
-
continue;
|
|
2284
|
-
}
|
|
2285
|
-
if (field.constraint.prim && slot.value.shape.k === "prim") {
|
|
2286
|
-
const actualPrim = slot.value.shape.type;
|
|
2287
|
-
if (actualPrim !== field.constraint.prim) {
|
|
2288
|
-
push(
|
|
2289
|
-
formatAbs(slot.value),
|
|
2290
|
-
`typeof ${key} = "${field.constraint.prim}"`,
|
|
2291
|
-
`change the return value's ${key} to ${field.constraint.prim}`
|
|
2292
|
-
);
|
|
2293
|
-
continue;
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
const lv2 = litValue(slot.value);
|
|
2297
|
-
if (lv2 !== void 0 && typeof lv2 === "number") {
|
|
2298
|
-
for (const p of field.constraint.preds) {
|
|
2299
|
-
const flat = p.op === "and" ? p.args : [p];
|
|
2300
|
-
for (const atom of flat) {
|
|
2301
|
-
if ((atom.op === "gt" || atom.op === "ge" || atom.op === "lt" || atom.op === "le") && atom.b.op === "lit" && typeof atom.b.value === "number") {
|
|
2302
|
-
const n = atom.b.value;
|
|
2303
|
-
let ok = true;
|
|
2304
|
-
if (atom.op === "gt") ok = lv2 > n;
|
|
2305
|
-
if (atom.op === "ge") ok = lv2 >= n;
|
|
2306
|
-
if (atom.op === "lt") ok = lv2 < n;
|
|
2307
|
-
if (atom.op === "le") ok = lv2 <= n;
|
|
2308
|
-
if (!ok) {
|
|
2309
|
-
const opSym = { gt: ">", ge: "\u2265", lt: "<", le: "\u2264" }[atom.op];
|
|
2310
|
-
push(
|
|
2311
|
-
formatAbs(slot.value),
|
|
2312
|
-
`${key} ${opSym} ${n}`,
|
|
2313
|
-
`the return value's ${key} should satisfy ${key} ${opSym} ${n}`
|
|
2314
|
-
);
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2320
2545
|
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
return
|
|
2328
|
-
|
|
2329
|
-
}
|
|
2330
|
-
const lv = litValue(ret);
|
|
2331
|
-
if (lv !== void 0 && typeof lv === "number") {
|
|
2332
|
-
for (const p of constraint.preds) {
|
|
2333
|
-
const flat = p.op === "and" ? p.args : [p];
|
|
2334
|
-
for (const atom of flat) {
|
|
2335
|
-
if ((atom.op === "gt" || atom.op === "ge" || atom.op === "lt" || atom.op === "le") && atom.b.op === "lit" && typeof atom.b.value === "number") {
|
|
2336
|
-
const n = atom.b.value;
|
|
2337
|
-
let ok = true;
|
|
2338
|
-
if (atom.op === "gt") ok = lv > n;
|
|
2339
|
-
if (atom.op === "ge") ok = lv >= n;
|
|
2340
|
-
if (atom.op === "lt") ok = lv < n;
|
|
2341
|
-
if (atom.op === "le") ok = lv <= n;
|
|
2342
|
-
if (!ok) {
|
|
2343
|
-
const opSym = { gt: ">", ge: "\u2265", lt: "<", le: "\u2264" }[atom.op];
|
|
2344
|
-
push(formatAbs(ret), `return ${opSym} ${n}`, `return a value satisfying ${opSym} ${n}`);
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
if (lv !== void 0 && (typeof lv === "number" || typeof lv === "string" || typeof lv === "boolean") && ((constraint.members?.length ?? 0) > 0 || constraint.preds.some((p) => p.op === "eq") || typeof lv === "string" && constraint.preds.length > 0) && !literalMeetsConstraint(lv, constraint)) {
|
|
2351
|
-
push(formatAbs(ret), formatConstraint(constraint), `return a value satisfying ${formatConstraint(constraint)}`);
|
|
2546
|
+
];
|
|
2547
|
+
if (proof.status === "disproved") {
|
|
2548
|
+
return push(
|
|
2549
|
+
"error",
|
|
2550
|
+
formatAbs(ret),
|
|
2551
|
+
proof.reason,
|
|
2552
|
+
proof.reason.includes("nullish") ? `use nullable(${formatConstraint(constraint)}) or union(..., lit(null)) to allow nullish returns` : `return a value satisfying ${formatConstraint(constraint)}`
|
|
2553
|
+
);
|
|
2352
2554
|
}
|
|
2353
|
-
return
|
|
2555
|
+
return push(
|
|
2556
|
+
"warning",
|
|
2557
|
+
formatAbs(ret),
|
|
2558
|
+
formatConstraint(constraint),
|
|
2559
|
+
`${proof.reason}; add a precondition, narrow the return expression, or relax the return contract`
|
|
2560
|
+
);
|
|
2354
2561
|
}
|
|
2355
2562
|
|
|
2356
2563
|
// src/algebra/check-report.ts
|
|
@@ -2386,6 +2593,12 @@ function actionsForIssue(i) {
|
|
|
2386
2593
|
];
|
|
2387
2594
|
case "nudo:entry-may-throw":
|
|
2388
2595
|
return [
|
|
2596
|
+
{
|
|
2597
|
+
kind: "draft",
|
|
2598
|
+
command: "nudo contract --draft",
|
|
2599
|
+
label: "narrow the entry with a sidecar fn({ \u2026 }) param contract \u2014 most honest fix for helpers (also tightens the signature)",
|
|
2600
|
+
...i.fn ? { hint: i.fn } : {}
|
|
2601
|
+
},
|
|
2389
2602
|
{
|
|
2390
2603
|
kind: "relax",
|
|
2391
2604
|
label: "declare intentional fail-fast: @nudo:throws Error (or case `!! throws`)",
|
|
@@ -2399,8 +2612,7 @@ function actionsForIssue(i) {
|
|
|
2399
2612
|
kind: "ignore-throws",
|
|
2400
2613
|
command: "nudo check --ignore-throws TypeError",
|
|
2401
2614
|
label: "migration switch: ignore this throw class on L2"
|
|
2402
|
-
}
|
|
2403
|
-
draft
|
|
2615
|
+
}
|
|
2404
2616
|
];
|
|
2405
2617
|
case "nudo:unknown-inference":
|
|
2406
2618
|
case "nudo:opaque-result":
|
|
@@ -2417,10 +2629,12 @@ function actionsForIssue(i) {
|
|
|
2417
2629
|
];
|
|
2418
2630
|
case "nudo:fork-truncated":
|
|
2419
2631
|
case "nudo:recursion-truncated":
|
|
2632
|
+
case "nudo:promise-micro-truncated":
|
|
2633
|
+
case "nudo:promise-micro-error":
|
|
2420
2634
|
return [
|
|
2421
2635
|
{
|
|
2422
2636
|
kind: "info",
|
|
2423
|
-
label: "results widened to unknown \u2014 raise budget or narrow control flow"
|
|
2637
|
+
label: "results widened to unknown \u2014 raise budget (@nudo:budget forks/calls/depth on the function) or narrow control flow"
|
|
2424
2638
|
}
|
|
2425
2639
|
];
|
|
2426
2640
|
case "nudo:host-effect-blocked":
|
|
@@ -2654,107 +2868,6 @@ function formatGitlabCodeQuality(r, opts = {}) {
|
|
|
2654
2868
|
};
|
|
2655
2869
|
});
|
|
2656
2870
|
}
|
|
2657
|
-
|
|
2658
|
-
// src/algebra/abs-modules.ts
|
|
2659
|
-
function bindImports(node, env, modules) {
|
|
2660
|
-
const mod2 = modules[node.source.value];
|
|
2661
|
-
if (!mod2) {
|
|
2662
|
-
for (const s of node.specifiers) {
|
|
2663
|
-
env.vars.set(s.local.name, unknown);
|
|
2664
|
-
}
|
|
2665
|
-
return;
|
|
2666
|
-
}
|
|
2667
|
-
for (const s of node.specifiers) {
|
|
2668
|
-
if (s.type === "ImportDefaultSpecifier") {
|
|
2669
|
-
env.vars.set(s.local.name, mod2.default ?? unknown);
|
|
2670
|
-
} else if (s.type === "ImportSpecifier") {
|
|
2671
|
-
const imported = s.imported.type === "Identifier" ? s.imported.name : String(s.imported);
|
|
2672
|
-
env.vars.set(s.local.name, mod2.named[imported] ?? unknown);
|
|
2673
|
-
} else if (s.type === "ImportNamespaceSpecifier") {
|
|
2674
|
-
const slots = {};
|
|
2675
|
-
for (const [k, v2] of Object.entries(mod2.named)) slots[k] = { value: v2 };
|
|
2676
|
-
if (mod2.default) slots["default"] = { value: mod2.default };
|
|
2677
|
-
env.vars.set(s.local.name, obj(slots));
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
}
|
|
2681
|
-
function fnToAbs(env, name) {
|
|
2682
|
-
const impl = env.fns.get(name);
|
|
2683
|
-
if (!impl) return void 0;
|
|
2684
|
-
return absFunction(impl.params, {
|
|
2685
|
-
body: impl.body,
|
|
2686
|
-
async: impl.async,
|
|
2687
|
-
env
|
|
2688
|
-
});
|
|
2689
|
-
}
|
|
2690
|
-
function lookupExport(env, name) {
|
|
2691
|
-
if (env.vars.has(name)) return env.vars.get(name);
|
|
2692
|
-
return fnToAbs(env, name);
|
|
2693
|
-
}
|
|
2694
|
-
function collectAbsExports(file, env, modules) {
|
|
2695
|
-
const named = {};
|
|
2696
|
-
let defaultExport;
|
|
2697
|
-
for (const stmt of file.program.body) {
|
|
2698
|
-
if (stmt.type === "ExportNamedDeclaration") {
|
|
2699
|
-
if (stmt.source && modules) {
|
|
2700
|
-
const mod2 = modules[stmt.source.value];
|
|
2701
|
-
if (mod2) {
|
|
2702
|
-
for (const spec of stmt.specifiers) {
|
|
2703
|
-
if (spec.type !== "ExportSpecifier") continue;
|
|
2704
|
-
const local = spec.local.type === "Identifier" ? spec.local.name : spec.local.value;
|
|
2705
|
-
const exported = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
|
|
2706
|
-
const v2 = local === "default" ? mod2.default : mod2.named[local];
|
|
2707
|
-
if (v2 === void 0) continue;
|
|
2708
|
-
if (exported === "default") defaultExport = v2;
|
|
2709
|
-
else named[exported] = v2;
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
continue;
|
|
2713
|
-
}
|
|
2714
|
-
const decl = stmt.declaration;
|
|
2715
|
-
if (decl) {
|
|
2716
|
-
if (decl.type === "FunctionDeclaration" && decl.id) {
|
|
2717
|
-
const v2 = lookupExport(env, decl.id.name);
|
|
2718
|
-
if (v2) named[decl.id.name] = v2;
|
|
2719
|
-
} else if (decl.type === "ClassDeclaration" && decl.id) {
|
|
2720
|
-
const v2 = lookupExport(env, decl.id.name);
|
|
2721
|
-
if (v2) named[decl.id.name] = v2;
|
|
2722
|
-
} else if (decl.type === "VariableDeclaration") {
|
|
2723
|
-
for (const d of decl.declarations) {
|
|
2724
|
-
if (d.id.type === "Identifier") {
|
|
2725
|
-
const v2 = lookupExport(env, d.id.name);
|
|
2726
|
-
if (v2) named[d.id.name] = v2;
|
|
2727
|
-
}
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2731
|
-
for (const spec of stmt.specifiers) {
|
|
2732
|
-
if (spec.type !== "ExportSpecifier") continue;
|
|
2733
|
-
const local = spec.local.type === "Identifier" ? spec.local.name : spec.local.value;
|
|
2734
|
-
const exported = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
|
|
2735
|
-
const v2 = lookupExport(env, local);
|
|
2736
|
-
if (v2) named[exported] = v2;
|
|
2737
|
-
}
|
|
2738
|
-
} else if (stmt.type === "ExportAllDeclaration" && stmt.source && modules) {
|
|
2739
|
-
const mod2 = modules[stmt.source.value];
|
|
2740
|
-
if (mod2?.named) {
|
|
2741
|
-
for (const [k, v2] of Object.entries(mod2.named)) named[k] = v2;
|
|
2742
|
-
}
|
|
2743
|
-
} else if (stmt.type === "ExportDefaultDeclaration") {
|
|
2744
|
-
const d = stmt.declaration;
|
|
2745
|
-
if (d.type === "FunctionDeclaration") {
|
|
2746
|
-
defaultExport = lookupExport(env, d.id ? d.id.name : "default");
|
|
2747
|
-
} else if (d.type === "ClassDeclaration" && d.id) {
|
|
2748
|
-
defaultExport = lookupExport(env, d.id.name);
|
|
2749
|
-
} else if (d.type === "Identifier") {
|
|
2750
|
-
defaultExport = lookupExport(env, d.name);
|
|
2751
|
-
}
|
|
2752
|
-
}
|
|
2753
|
-
}
|
|
2754
|
-
const result = { named };
|
|
2755
|
-
if (defaultExport) result.default = defaultExport;
|
|
2756
|
-
return result;
|
|
2757
|
-
}
|
|
2758
2871
|
export {
|
|
2759
2872
|
$add,
|
|
2760
2873
|
$arguments,
|
|
@@ -2847,6 +2960,7 @@ export {
|
|
|
2847
2960
|
$thisSet,
|
|
2848
2961
|
$throw,
|
|
2849
2962
|
$toNumber,
|
|
2963
|
+
$toNumeric,
|
|
2850
2964
|
$tryCurrentMark,
|
|
2851
2965
|
$tryDetachSoftCatch,
|
|
2852
2966
|
$tryDigestSoftCatch,
|
|
@@ -2859,6 +2973,8 @@ export {
|
|
|
2859
2973
|
$tryTakeSince,
|
|
2860
2974
|
$typeof,
|
|
2861
2975
|
$unknown,
|
|
2976
|
+
$updateAdd,
|
|
2977
|
+
$updateSub,
|
|
2862
2978
|
$ushr,
|
|
2863
2979
|
$while,
|
|
2864
2980
|
$whileSeq,
|
|
@@ -2895,6 +3011,7 @@ export {
|
|
|
2895
3011
|
asAbs,
|
|
2896
3012
|
asAbsVal,
|
|
2897
3013
|
assignSourceSlots,
|
|
3014
|
+
assumeFinite,
|
|
2898
3015
|
attachFnImpl,
|
|
2899
3016
|
beginCollectionFork,
|
|
2900
3017
|
betaOf,
|
|
@@ -2928,6 +3045,7 @@ export {
|
|
|
2928
3045
|
collectionElementJoin,
|
|
2929
3046
|
collectionExactLen,
|
|
2930
3047
|
confJoin,
|
|
3048
|
+
constraintAdmitsNullish,
|
|
2931
3049
|
constraintToEntryAbs,
|
|
2932
3050
|
contractParamNameSet,
|
|
2933
3051
|
createEnvironment,
|
|
@@ -2974,6 +3092,7 @@ export {
|
|
|
2974
3092
|
extStateOf,
|
|
2975
3093
|
extractDeclaredThrows,
|
|
2976
3094
|
extractFn,
|
|
3095
|
+
extractFnBudget,
|
|
2977
3096
|
extractNudoImports,
|
|
2978
3097
|
extractRefineReturnFromSource,
|
|
2979
3098
|
extractRefinesFromSource,
|
|
@@ -2985,6 +3104,7 @@ export {
|
|
|
2985
3104
|
foldRequireSpecArg,
|
|
2986
3105
|
foldStaticStringExpr,
|
|
2987
3106
|
formalParamDisplayNames,
|
|
3107
|
+
formalParamSignatureNames,
|
|
2988
3108
|
formalParamsFromNodes,
|
|
2989
3109
|
formatAbs,
|
|
2990
3110
|
formatAbsMultiline,
|
|
@@ -3090,6 +3210,7 @@ export {
|
|
|
3090
3210
|
mock,
|
|
3091
3211
|
mod,
|
|
3092
3212
|
mul,
|
|
3213
|
+
namespaceAbsOf,
|
|
3093
3214
|
namespaceNameOf,
|
|
3094
3215
|
ne,
|
|
3095
3216
|
negAbs,
|
|
@@ -3101,6 +3222,7 @@ export {
|
|
|
3101
3222
|
noteEvalCallRecord,
|
|
3102
3223
|
noteEvalFallback,
|
|
3103
3224
|
notePromiseExecutorFork,
|
|
3225
|
+
nullable,
|
|
3104
3226
|
num,
|
|
3105
3227
|
numLit,
|
|
3106
3228
|
numVar,
|
|
@@ -3126,6 +3248,7 @@ export {
|
|
|
3126
3248
|
primToTypeof,
|
|
3127
3249
|
projectFlatMapResult,
|
|
3128
3250
|
promoteParamShape,
|
|
3251
|
+
propertyKeyOf,
|
|
3129
3252
|
protoBrandAbs,
|
|
3130
3253
|
protoOfRecv,
|
|
3131
3254
|
ptypeof,
|
|
@@ -3149,6 +3272,7 @@ export {
|
|
|
3149
3272
|
resetNudoModuleExecCache,
|
|
3150
3273
|
resetParseSourceCache,
|
|
3151
3274
|
resetPhi,
|
|
3275
|
+
resetSidecarLoadFailureCache,
|
|
3152
3276
|
runTranspiled,
|
|
3153
3277
|
runTranspiledOptionsMemoKey,
|
|
3154
3278
|
runWithLoopExits,
|