@nudojs/core 1.1.0 → 1.1.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.
@@ -10504,6 +10504,10 @@ var _bForkBudgetLimit = MAX_B_TOTAL_FORKS;
10504
10504
  var _bForkCount = 0;
10505
10505
  var _bForkTruncNoted = false;
10506
10506
  var FORK_TRUNCATION_LABEL = "#fork-budget";
10507
+ var HOST_EFFECT_LABEL_PREFIX = "#host-effect:";
10508
+ function noteHostEffectBlocked(name) {
10509
+ noteAbsTruncation(`${HOST_EFFECT_LABEL_PREFIX}${name}`);
10510
+ }
10507
10511
  function noteBForkTruncation() {
10508
10512
  noteAbsTruncation(FORK_TRUNCATION_LABEL);
10509
10513
  }
@@ -12578,6 +12582,26 @@ var GLOBAL_FNS = /* @__PURE__ */ new Set([
12578
12582
  "eval",
12579
12583
  "Symbol"
12580
12584
  ]);
12585
+ var NEVER_EXEC_HOST_FN_NAMES = [
12586
+ "fetch",
12587
+ "XMLHttpRequest",
12588
+ "WebSocket",
12589
+ "EventSource",
12590
+ "setTimeout",
12591
+ "setInterval",
12592
+ "setImmediate",
12593
+ "queueMicrotask",
12594
+ "requestAnimationFrame",
12595
+ "requestIdleCallback"
12596
+ ];
12597
+ function neverExecHostName(fn) {
12598
+ if (typeof fn !== "function") return null;
12599
+ const g = globalThis;
12600
+ for (const n of NEVER_EXEC_HOST_FN_NAMES) {
12601
+ if (fn === g[n]) return n;
12602
+ }
12603
+ return null;
12604
+ }
12581
12605
  function noteBCallRecord(r) {
12582
12606
  if (!bCallCollector) return;
12583
12607
  try {
@@ -12659,8 +12683,12 @@ function $callNamed(name, fn, args, loc, argLocs) {
12659
12683
  try {
12660
12684
  if (typeof fn === "function") {
12661
12685
  const g = GLOBAL_FNS.has(name) && fn === globalThis[name] ? evalGlobalFn(name, args) : void 0;
12686
+ const blockedHost = g === void 0 ? neverExecHostName(fn) : null;
12662
12687
  if (g !== void 0) {
12663
12688
  result = g;
12689
+ } else if (blockedHost !== null) {
12690
+ noteHostEffectBlocked(blockedHost);
12691
+ result = bTruncatedAbs();
12664
12692
  } else {
12665
12693
  const entered = bEnterCall(name, fn, args);
12666
12694
  if (!entered.ok) {
@@ -12759,7 +12787,13 @@ function execRegexBrand(re, method, args) {
12759
12787
  if (method === "toString") return strLit(`/${parts.pat}/${parts.flags}`);
12760
12788
  const subject = args[0] ? litValue(args[0]) : void 0;
12761
12789
  if (typeof subject !== "string") {
12762
- return method === "test" ? abs({ k: "prim", type: "boolean" }, void 0, void 0, "partial") : void 0;
12790
+ if (method === "test") {
12791
+ return abs({ k: "prim", type: "boolean" }, void 0, void 0, "partial");
12792
+ }
12793
+ const element = joinAbs(str(), undefAbs());
12794
+ const matchAbs = abs({ k: "arr", element }, void 0, void 0, "path");
12795
+ const nullAbs = abs({ k: "unknown" }, { op: "lit", value: null }, void 0, "exact");
12796
+ return joinAbs(nullAbs, matchAbs);
12763
12797
  }
12764
12798
  try {
12765
12799
  return regexExecWithState(re, method, subject).result;
@@ -14936,6 +14970,8 @@ export {
14936
14970
  exitCall,
14937
14971
  MAX_B_TOTAL_FORKS,
14938
14972
  FORK_TRUNCATION_LABEL,
14973
+ HOST_EFFECT_LABEL_PREFIX,
14974
+ noteHostEffectBlocked,
14939
14975
  noteBForkTruncation,
14940
14976
  setBForkBudgetLimit,
14941
14977
  getBForkBudgetLimit,
@@ -41,7 +41,7 @@ import {
41
41
  unknown,
42
42
  v,
43
43
  withExecPhi
44
- } from "./chunk-MA2QEIYC.js";
44
+ } from "./chunk-CDH7QCGQ.js";
45
45
 
46
46
  // src/algebra/constraint.ts
47
47
  var SELF = "__nudo_self__";
package/dist/exec.js CHANGED
@@ -162,7 +162,7 @@ import {
162
162
  transpileSource,
163
163
  tryRunTranspiled,
164
164
  withExecPhi
165
- } from "./chunk-MA2QEIYC.js";
165
+ } from "./chunk-CDH7QCGQ.js";
166
166
  export {
167
167
  $add,
168
168
  $arguments,
package/dist/index.js CHANGED
@@ -67,7 +67,7 @@ import {
67
67
  takeRefineDiagsSince,
68
68
  throwConstraintToKinds,
69
69
  union
70
- } from "./chunk-ZUQXJRJL.js";
70
+ } from "./chunk-V2I7VXFZ.js";
71
71
  import {
72
72
  $add,
73
73
  $arguments,
@@ -178,6 +178,7 @@ import {
178
178
  $yield,
179
179
  DEFAULT_MAX_LOOP_ITERS,
180
180
  FORK_TRUNCATION_LABEL,
181
+ HOST_EFFECT_LABEL_PREFIX,
181
182
  MAX_B_CALL_DEPTH,
182
183
  MAX_B_TOTAL_CALLS,
183
184
  NudoLoopSignal,
@@ -465,7 +466,7 @@ import {
465
466
  v,
466
467
  withExecPhi,
467
468
  withVar
468
- } from "./chunk-MA2QEIYC.js";
469
+ } from "./chunk-CDH7QCGQ.js";
469
470
 
470
471
  // src/environment.ts
471
472
  function createEnvironment(parent, bindings = /* @__PURE__ */ new Map()) {
@@ -2101,6 +2102,17 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
2101
2102
  });
2102
2103
  continue;
2103
2104
  }
2105
+ if (label.startsWith(HOST_EFFECT_LABEL_PREFIX)) {
2106
+ const hostName = label.slice(HOST_EFFECT_LABEL_PREFIX.length);
2107
+ issues.push({
2108
+ severity: "info",
2109
+ code: "nudo:host-effect-blocked",
2110
+ message: `Host function '${hostName}' is not executed during analysis (network/timer side effect); result widened to unknown#opaque`,
2111
+ suggestion: "optional: mock it with @nudo:mock / @nudo:env, or pass the value in from a call site",
2112
+ fn: hostName
2113
+ });
2114
+ continue;
2115
+ }
2104
2116
  issues.push({
2105
2117
  severity: "info",
2106
2118
  code: "nudo:recursion-truncated",
@@ -2230,6 +2242,19 @@ function checkReturnConstraint(fnName, cName, constraint, ret) {
2230
2242
  const out = [];
2231
2243
  if (ret.shape.k === "unknown" && !ret.term) return out;
2232
2244
  if (ret.shape.k === "any") return out;
2245
+ if (isNullishLitAbs(ret)) return out;
2246
+ if (ret.shape.k === "sum" && constraint.fields) {
2247
+ const seen = /* @__PURE__ */ new Set();
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
+ }
2233
2258
  const push = (actual, expected, suggestion) => {
2234
2259
  out.push({
2235
2260
  severity: "error",
@@ -2398,6 +2423,11 @@ function actionsForIssue(i) {
2398
2423
  label: "results widened to unknown \u2014 raise budget or narrow control flow"
2399
2424
  }
2400
2425
  ];
2426
+ case "nudo:host-effect-blocked":
2427
+ return [
2428
+ { kind: "mock", label: "pin the host API with @nudo:mock / @nudo:env" },
2429
+ { kind: "info", label: "results widened to unknown \u2014 or feed the value in from a call site" }
2430
+ ];
2401
2431
  case "nudo:interface-drift":
2402
2432
  return [
2403
2433
  {
@@ -65,6 +65,15 @@ declare const MAX_B_TOTAL_FORKS = 5000;
65
65
  * 映射为 `nudo:fork-truncated`(warning)。
66
66
  */
67
67
  declare const FORK_TRUNCATION_LABEL = "#fork-budget";
68
+ /**
69
+ * 宿主副作用未执行标签前缀:网络/定时器全局(fetch/setTimeout…)在分析期
70
+ * 不真实执行(Abs 实参喂原生实现会真发请求/真排定时器,且可能崩进程),
71
+ * fail-closed 为 unknown#opaque。专用前缀让 check 映射为
72
+ * `nudo:host-effect-blocked`,不复用「某函数被截断」文案。
73
+ */
74
+ declare const HOST_EFFECT_LABEL_PREFIX = "#host-effect:";
75
+ /** 宿主副作用未执行观测(service/LSP 映射 nudo:host-effect-blocked;与调用截断同 collector 管道) */
76
+ declare function noteHostEffectBlocked(name: string): void;
68
77
  /** fork 超限观测(service/LSP 映射 nudo:fork-truncated;与调用截断同 collector 管道) */
69
78
  declare function noteBForkTruncation(): void;
70
79
  /**
@@ -538,4 +547,4 @@ declare function runWithEvalMissingSlot<T>(enabled: boolean, body: () => T): T;
538
547
  */
539
548
  declare function noteObjSlotMissing(recv: Abs | undefined, name: string, loc?: [number, number]): boolean;
540
549
 
541
- export { type AbsBudgetStats, type AbsInlay, type ArgDerivation, type BMemberDiag, type ClassDef, type CollectAbsInlaysOpts, type DerivationNode, FORK_TRUNCATION_LABEL, type FnFp, type InjectedDomainEvidenceOpts, type InjectedDomainRecord, MAX_B_TOTAL_FORKS, MAX_CALL_DEPTH, MAX_TOTAL_CALLS, type MethodDef, OBJECT_PROTO_NAMES, type TemplateMeta, type TemplatePartDesc, type TemplatePartView, type TemplatePredicateDecision, abortDerivationSession, absTemplateViews, allFixedTextOfViews, anyMemberResult, awaitAbs, beginDerivationSession, bumpBForkBudget, callBudgetKey, canSkipLiteralCallScan, checkInjectedDomainEvidence, classChainNames, classFromMethods, coerceAsyncReturn, collectAbsInlays, concatString, createTemplateAbs, decideEndsWith, decideIncludes, decideStartsWith, defineClass, definitelyUncallableMember, denoteGuard, derivationChain, endDerivationSession, enterCall, exitCall, fixedLengthOfViews, fnFingerprints, formatTemplateNameViews, generalizeSourceKeyPart, getAbsCallBudgetStats, getAbsOrigin, getBForkBudgetLimit, getBForkCount, getClass, getClassChain, getDerivation, getFnNameAndBodies, hasDerivationSession, hashSource, instanceOf, instantiateClass, isEvalMissingSlotEnabled, isNullishAbs, isTemplateLike, knownPrefixOfViews, knownSuffixOfViews, listTopFunctions, lookupMethod, lookupMethodWithOwner, lookupSuperMethod, mergeAdjacentFixedViews, noteAbsTruncation, noteAnyMemberMayThrow, noteBForkTruncation, noteDerivationAdd, noteDerivationJoin, noteMemberDispatchMiss, noteNullishMemberThrows, noteObjSlotMissing, notePrimMemberMissing, noteUnknownMemberMissing, popCallLoc, projectBrand, projectDerivationDsl, pushCallLoc, recordMemberDiag, resetAbsCallBudget, resetBForkBudget, resetFnFpCache, resetHashSourceCache, runWithEvalMissingSlot, setAbsTruncationCollector, setBForkBudgetLimit, setDerivation, setDerivationCollector, setEvalMissingSlotEnabled, setMemberDiagCollector, stableAnalyzeKeySource, stableCallId, superNameOf, tagAbsOrigin, tagDerivationRoot, templateMatchesValue, templatePartsOf, termKey, truncatedAbs, viewTemplateParts, wrapPromise };
550
+ export { type AbsBudgetStats, type AbsInlay, type ArgDerivation, type BMemberDiag, type ClassDef, type CollectAbsInlaysOpts, type DerivationNode, FORK_TRUNCATION_LABEL, type FnFp, HOST_EFFECT_LABEL_PREFIX, type InjectedDomainEvidenceOpts, type InjectedDomainRecord, MAX_B_TOTAL_FORKS, MAX_CALL_DEPTH, MAX_TOTAL_CALLS, type MethodDef, OBJECT_PROTO_NAMES, type TemplateMeta, type TemplatePartDesc, type TemplatePartView, type TemplatePredicateDecision, abortDerivationSession, absTemplateViews, allFixedTextOfViews, anyMemberResult, awaitAbs, beginDerivationSession, bumpBForkBudget, callBudgetKey, canSkipLiteralCallScan, checkInjectedDomainEvidence, classChainNames, classFromMethods, coerceAsyncReturn, collectAbsInlays, concatString, createTemplateAbs, decideEndsWith, decideIncludes, decideStartsWith, defineClass, definitelyUncallableMember, denoteGuard, derivationChain, endDerivationSession, enterCall, exitCall, fixedLengthOfViews, fnFingerprints, formatTemplateNameViews, generalizeSourceKeyPart, getAbsCallBudgetStats, getAbsOrigin, getBForkBudgetLimit, getBForkCount, getClass, getClassChain, getDerivation, getFnNameAndBodies, hasDerivationSession, hashSource, instanceOf, instantiateClass, isEvalMissingSlotEnabled, isNullishAbs, isTemplateLike, knownPrefixOfViews, knownSuffixOfViews, listTopFunctions, lookupMethod, lookupMethodWithOwner, lookupSuperMethod, mergeAdjacentFixedViews, noteAbsTruncation, noteAnyMemberMayThrow, noteBForkTruncation, noteDerivationAdd, noteDerivationJoin, noteHostEffectBlocked, noteMemberDispatchMiss, noteNullishMemberThrows, noteObjSlotMissing, notePrimMemberMissing, noteUnknownMemberMissing, popCallLoc, projectBrand, projectDerivationDsl, pushCallLoc, recordMemberDiag, resetAbsCallBudget, resetBForkBudget, resetFnFpCache, resetHashSourceCache, runWithEvalMissingSlot, setAbsTruncationCollector, setBForkBudgetLimit, setDerivation, setDerivationCollector, setEvalMissingSlotEnabled, setMemberDiagCollector, stableAnalyzeKeySource, stableCallId, superNameOf, tagAbsOrigin, tagDerivationRoot, templateMatchesValue, templatePartsOf, termKey, truncatedAbs, viewTemplateParts, wrapPromise };
package/dist/internal.js CHANGED
@@ -16,13 +16,14 @@ import {
16
16
  resolveDepPath,
17
17
  sidecarSpecsOf,
18
18
  stableAnalyzeKeySource
19
- } from "./chunk-ZUQXJRJL.js";
19
+ } from "./chunk-V2I7VXFZ.js";
20
20
  import {
21
21
  $tryDigestSoft,
22
22
  $tryMarkSoft,
23
23
  $tryReleaseSoft,
24
24
  ERROR_FAMILY,
25
25
  FORK_TRUNCATION_LABEL,
26
+ HOST_EFFECT_LABEL_PREFIX,
26
27
  MAX_B_TOTAL_FORKS,
27
28
  MAX_CALL_DEPTH,
28
29
  MAX_TOTAL_CALLS,
@@ -90,6 +91,7 @@ import {
90
91
  noteBForkTruncation,
91
92
  noteDerivationAdd,
92
93
  noteDerivationJoin,
94
+ noteHostEffectBlocked,
93
95
  noteMemberDispatchMiss,
94
96
  noteNullishMemberThrows,
95
97
  noteObjSlotMissing,
@@ -133,7 +135,7 @@ import {
133
135
  truncatedAbs,
134
136
  viewTemplateParts,
135
137
  wrapPromise
136
- } from "./chunk-MA2QEIYC.js";
138
+ } from "./chunk-CDH7QCGQ.js";
137
139
 
138
140
  // src/algebra/inlay.ts
139
141
  function listFunctions(source) {
@@ -458,6 +460,7 @@ export {
458
460
  $tryReleaseSoft,
459
461
  ERROR_FAMILY,
460
462
  FORK_TRUNCATION_LABEL,
463
+ HOST_EFFECT_LABEL_PREFIX,
461
464
  MAX_B_TOTAL_FORKS,
462
465
  MAX_CALL_DEPTH,
463
466
  MAX_TOTAL_CALLS,
@@ -535,6 +538,7 @@ export {
535
538
  noteBForkTruncation,
536
539
  noteDerivationAdd,
537
540
  noteDerivationJoin,
541
+ noteHostEffectBlocked,
538
542
  noteMemberDispatchMiss,
539
543
  noteNullishMemberThrows,
540
544
  noteObjSlotMissing,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudojs/core",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },