@nudojs/core 1.15.0 → 1.16.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.
@@ -1,11 +1,12 @@
1
1
  import { File } from '@babel/types';
2
- import { A as Abs, T as Term, P as PrimName, a as Pred, L as LiteralValue, b as Phi, C as Confidence } from './run-DfloWX6i.js';
2
+ import { A as Abs, T as Term, P as PrimName, a as Pred, L as LiteralValue, C as Confidence, b as Phi } from './run-T9HWTziZ.js';
3
3
 
4
4
  declare function resetParseSourceCache(): void;
5
5
  declare function getParseSourceCacheSize(): number;
6
6
  declare function parseSource(source: string, opts?: {
7
7
  errorRecovery?: boolean;
8
8
  keepTs?: boolean;
9
+ filename?: string;
9
10
  }): File;
10
11
 
11
12
  /**
@@ -30,7 +31,12 @@ declare function drainPromiseMicros(): void;
30
31
  declare function evalPromiseCtor(args: Abs[]): Abs;
31
32
  /** then/catch/finally:可映射回调 → 新 inner;做不到诚实 promise<unknown> */
32
33
  declare function evalPromiseMethod(name: string, recv: Abs, args: Abs[]): Abs | undefined;
33
- declare function evalPromiseStatic(name: string, args: Abs[]): Abs | undefined;
34
+ /**
35
+ * Bug 311:Promise 静态派发。thisVal = 静态方法值的 this 绑定(成员读出
36
+ * 的静态方法被单独调用时的接收者);缺席 = 直接命名空间调用(this ≡
37
+ * Promise 构造器,合法)。非构造器接收者按原生抛 TypeError。
38
+ */
39
+ declare function evalPromiseStatic(name: string, args: Abs[], thisVal?: Abs): Abs | undefined;
34
40
 
35
41
  /**
36
42
  * 项(Term)防爆炸:深度/宽度阈值 → leak 为新鲜 var + 等式约束。
@@ -87,6 +93,11 @@ declare function isNodeModulesPath(p: string): boolean;
87
93
  * 源文件的旁路侧车路径:.js/.mjs → 同名 .nudo.js;.ts/.mts → 同名 .nudo.ts。
88
94
  * 其他扩展名(.cjs/.jsx/无扩展名…)不做替换,直接追加 .nudo.js——侧车约定
89
95
  * 只覆盖四类入口;host loadModule 对不存在的路径返回 miss,自然无侧车来源。
96
+ *
97
+ * **幂等**(Bug 362):输入本身已是侧车(`lib.nudo.js` / `lib.nudo.ts`)时
98
+ * **不再追加第二段** `.nudo`。旧口径产出 `lib.nudo.nudo.js`——该路径不是任何
99
+ * 源码的侧车 ⇒ 契约永久静默失效;草稿面还会落到 `lib.nudo.nudo.draft.js`
100
+ * 并指示用户「copy it into lib.nudo.nudo.js」(一个不存在的侧车名)。
90
101
  */
91
102
  declare function sidecarPathOf(file: string): string;
92
103
 
@@ -163,14 +174,26 @@ declare function string(): ConstraintBuilder;
163
174
  declare function boolean(): ConstraintBuilder;
164
175
  /** any() —— 无约束;formatConstraint / draft import 与显示同源 */
165
176
  declare function any(): ConstraintBuilder;
166
- /** array(item) —— 数组,元素满足 item;item 亦可为具体字面量(指令文法) */
167
- declare function array(item: NudoConstraint | ConstraintBuilder | number | string | boolean | null | undefined): ConstraintBuilder;
177
+ /**
178
+ * array(item) —— 数组,元素满足 item;item 亦可为具体字面量(指令文法)。
179
+ *
180
+ * 元素约束**必填**(Bug 354):少传元素时旧实现把 `undefined` 交给
181
+ * asNestedConstraint ⇒ 静默变成 `lit(undefined)` ⇒ 契约变成「元素必须是
182
+ * undefined」⇒ 任何合法数组实参都被判违反(假红),且零诊断说明缺参。
183
+ * 「元素可为 undefined」有显式写法:`array(lit(undefined))`。
184
+ */
185
+ declare function array(item: NudoConstraint | ConstraintBuilder | number | string | boolean | null | undefined, ...rest: unknown[]): ConstraintBuilder;
168
186
  /**
169
187
  * object 形状约束(契约规范形状,无需 interface):
170
188
  *
171
189
  * shape({ id: number().gt(0), name: string() })
172
190
  *
173
191
  * 字段值亦可为具体字面量(指令文法)。
192
+ *
193
+ * 实参守卫(Bug 352 / 353):缺参 ⇒ 点名构造器 + 说明缺参;非对象 ⇒ 点名
194
+ * 构造器 + 实际类型。旧实现把实参直接交给 `Object.entries`:`shape(42)` ⇒
195
+ * `[]` ⇒ 整条参数契约退化成空 shape(域放宽到任意对象 = 假绿);`shape()`
196
+ * ⇒ 宿主 TypeError「Cannot convert undefined or null to object」原文进诊断。
174
197
  */
175
198
  declare function shape(fields: Record<string, NudoConstraint | ConstraintBuilder | number | string | boolean | null | undefined>): ConstraintBuilder;
176
199
  /** litC(v):字面量契约——prim 按 v 类型、eq(self, v) pred 编码(不开新字段) */
@@ -216,6 +239,11 @@ declare function constraintAdmitsNullish(c: NudoConstraint, seen?: Set<object>):
216
239
  * fn(params, returns?, { throws? }):一等函数约束。
217
240
  * Phase 1 只展示不执法:参数位 instantiate 恒真(pTrue),
218
241
  * 逐参约束经 fnConstraintToEntryReqs 消费。
242
+ *
243
+ * 第三实参(opts)做**形态校验**(Bug 357):
244
+ * - opts 必须是对象 —— 否则整条 throws 申报被静默丢弃(零诊断假红);
245
+ * - opts.throws 归一后必须能抽出至少一个错误名(throwConstraintToKinds 非
246
+ * undefined)—— 否则 throws 义务无声消失,用户已申报却仍报 may-throw。
219
247
  */
220
248
  declare function fn(params: Record<string, NudoConstraint | ConstraintBuilder | number | string | boolean | null | undefined>, returns?: NudoConstraint | ConstraintBuilder | number | string | boolean | null | undefined, opts?: {
221
249
  throws?: NudoConstraint | ConstraintBuilder | number | string | boolean | null | undefined;
@@ -226,11 +254,30 @@ declare function fn(params: Record<string, NudoConstraint | ConstraintBuilder |
226
254
  * prim 不一致或任一含 fields/element/members/fn → throw。
227
255
  */
228
256
  declare function andC(...cs: (NudoConstraint | ConstraintBuilder)[]): ConstraintBuilder;
229
- /** partial(c):shape 全字段变可选;非 shape throw(lazy 包装先解一层) */
257
+ /**
258
+ * partial(c):shape 全字段变可选;非 shape throw(lazy 包装先解一层)。
259
+ *
260
+ * 写侧用**无原型字段表**(Bug 1027):partial 是「读旧表 ⇒ 写新表」,
261
+ * 若新表是普通对象,字段名 `__proto__` 会被原型 setter 吞掉 ⇒ 经 partial
262
+ * 转一道仍二次吞键 ⇒ 契约被削弱成空 shape。
263
+ */
230
264
  declare function partial(c: NudoConstraint | ConstraintBuilder): ConstraintBuilder;
231
- /** pick(c, keys):shape 子形状(不存在的 key 忽略);非 shape throw(lazy 包装先解一层) */
265
+ /**
266
+ * pick(c, keys):shape 子形状(不存在的 key 忽略);非 shape throw(lazy 包装先解一层)。
267
+ *
268
+ * 字段读取用**自有属性**判定(Bug 347):`d.fields[k]` 沿原型链读,
269
+ * "constructor" / "toString" 会命中 Object.prototype 成员并被当成字段塞进
270
+ * 新字段表 ⇒ 后续读 `f.constraint` 拿到 undefined ⇒ contract / export 面裸崩、
271
+ * check 面静默作废整条契约。
272
+ */
232
273
  declare function pick(c: NudoConstraint | ConstraintBuilder, keys: string[]): ConstraintBuilder;
233
- /** omit(c, keys):shape 去字段;非 shape throw(lazy 包装先解一层) */
274
+ /**
275
+ * omit(c, keys):shape 去字段;非 shape throw(lazy 包装先解一层)。
276
+ *
277
+ * 写侧用**无原型字段表**(Bug 1027):omit 是「读旧表 ⇒ 写新表」,
278
+ * 若新表是普通对象,字段名 `__proto__` 会被原型 setter 吞掉 ⇒ 经 omit
279
+ * 转一道仍二次吞键 ⇒ 契约被削弱成空 shape。
280
+ */
234
281
  declare function omit(c: NudoConstraint | ConstraintBuilder, keys: string[]): ConstraintBuilder;
235
282
  /**
236
283
  * 约束构建器表面名表(单一真源):case 实参文法、mock 类型表达式识别与
@@ -311,6 +358,9 @@ type RefineDiag = {
311
358
  code: string;
312
359
  message: string;
313
360
  file?: string;
361
+ /** Bug 374:诊断位置(1-based 行 / 0-based 列;与 Babel loc 同坐标面) */
362
+ line?: number;
363
+ column?: number;
314
364
  };
315
365
  /** 设置诊断观察者(null 清除);缓冲照常累积,takeRefineDiags 取走 */
316
366
  declare function setRefineDiagCollector(fn: ((d: RefineDiag) => void) | null): void;
@@ -354,6 +404,9 @@ declare function refineToIndexedFull(source: string, fnName: string, paramNames:
354
404
  /**
355
405
  * 解析 `@nudo:contract return positive` → 返回契约。
356
406
  * 返回 undefined = 无声明(不猜后置)。
407
+ *
408
+ * Bug 360:多条 return 段**合成单条合取**(不再「首个命中即 return」)。
409
+ * Bug 351:fn 形态模板取其 `fn.returns`(与侧车口径一致,返回义务真被执法)。
357
410
  */
358
411
  declare function extractRefineReturnFromSource(source: string, fnName: string, opts?: RefineResolveOpts): {
359
412
  name: string;
@@ -369,6 +422,11 @@ declare function extractRefineReturnFromSource(source: string, fnName: string, o
369
422
  *
370
423
  * 与 refine 同扫函数前注释块(D6=G2 同一 scope 绑定)。
371
424
  * 返回 `*` = 申报任意;数组 = 按名申报;undefined = 无申报(L2 照常执法)。
425
+ *
426
+ * Bug 1032:粘连(`@nudo:throwsTypeError`)与**空载荷**(`@nudo:throws`)此前
427
+ * **整行不匹配**严格正则且**无 else 分支** ⇒ 抛错申报**零诊断**地蒸发 ⇒ L2
428
+ * 门禁按「未申报」执法(假红),而用户以为申报生效了 ⇒ 这里显式发
429
+ * `nudo:directive-syntax`(既有码,不另造新码)。
372
430
  */
373
431
  declare function extractDeclaredThrows(source: string, fnName: string): string[] | "*" | undefined;
374
432
  /**
@@ -414,10 +472,16 @@ declare function localNamedExports(source: string): Set<string>;
414
472
  */
415
473
  declare function exportedNameOfLocal(source: string, localName: string): string | undefined;
416
474
  /**
417
- * 侧车源码的生成段导出名:export 之前(跳过紧邻的 import/const 链)的注释
418
- * 行含 `@generated` → 该名为 generated。组合式下行段(§5.3)形态为
419
- * `import` + `@generated 头` + prelude + export;callsite 段则是头紧贴
420
- * export。隔了其他代码行 / 无标记 / re-export 列表均不算。
475
+ * 侧车源码的生成段导出名:export 之前(跳过紧邻的 import 链与**被 export
476
+ * 引用**的 const 链)的注释行是 nudo 自己的 `@generated` 标记 → 该名为
477
+ * generated。组合式下行段(§5.3)形态为 `import` + `@generated 头` + prelude +
478
+ * export;callsite 段则是头紧贴 export。隔了其他代码行 / 无标记 / re-export
479
+ * 列表均不算。
480
+ *
481
+ * 标记判定是**精确**的(Bug 440):注释首个记号必须是 `@generated` 且点名 nudo
482
+ * ——散文里**提到** `@generated` 不算(那是用户引用 nudo 的提示语)。
483
+ * 段边界也**收紧**(Bug 432):紧邻的 const 只有**被该 export 引用**时才属
484
+ * 段内,用户自己的 const 夹在中间 ⇒ 上一段的标记不落进本段。
421
485
  *
422
486
  * DESIGN-003 别名段:导出名不是合法绑定名(保留字 / 非 ident)时发射为
423
487
  * `const _nudo_1 = …; export { _nudo_1 as class };` —— 身份恒为**导出名**
@@ -459,6 +523,9 @@ type InterfaceDiag = {
459
523
  code: string;
460
524
  message: string;
461
525
  file?: string;
526
+ /** Bug 374:诊断位置(1-based 行 / 0-based 列;转发 refine 诊断时透传) */
527
+ line?: number;
528
+ column?: number;
462
529
  };
463
530
  /** 设置诊断观察者(null 清除);缓冲照常累积,takeInterfaceDiags 取走 */
464
531
  declare function setInterfaceDiagCollector(fn: ((d: InterfaceDiag) => void) | null): void;
@@ -513,6 +580,17 @@ type EffectiveInterface = {
513
580
  params: string[];
514
581
  returns?: boolean;
515
582
  };
583
+ /**
584
+ * 合取**不可判定**标记(Bug 1141):结构型组合(union / fn / 结构型∧标量…)
585
+ * 算不出交集 —— 不是「不可满足」(不标 conflict、既有义务继续执法),但
586
+ * **另一侧**的义务确实没被执法 ⇒ 显式报出(不得静默宽松)。
587
+ *
588
+ * 独立于 `conflict`:conflict 的语义是「矛盾 ⇒ 跳过该位执法」,两者不可混。
589
+ */
590
+ undecidable?: {
591
+ params: string[];
592
+ returns?: boolean;
593
+ };
516
594
  };
517
595
  /** 与 resetNudoModuleExecCache 同口径:分析会话/测试间清空失败去重表 */
518
596
  declare function resetSidecarLoadFailureCache(): void;
@@ -582,10 +660,35 @@ type LoadDepsFingerprint = {
582
660
  */
583
661
  readError: boolean;
584
662
  };
663
+ /**
664
+ * 指纹的 ambient 侧车探测口径(Bug 1124)。
665
+ *
666
+ * ambient 侧车探测是**推测性**的:它只为算指纹,不代表分析真的要用这份侧车
667
+ * (autoBind 关 / 树外 / node_modules ⇒ 根本不会被绑定)。⇒ 探测失败
668
+ * **不得**升级成分析错误(门禁假红),但仍须让本轮指纹**不可信**
669
+ * (readError ⇒ 键带 readerr: 前缀、调用方 fail-open 禁 memo ⇒ 错误轮与
670
+ * miss 轮不共用键、互不为陈旧命中)。
671
+ */
672
+ type LoadDepsFingerprintOpts = {
673
+ /**
674
+ * ambient 侧车探测专用 loader(**推测性**读)。
675
+ * 调用方(check.ts)传**未经降级闸**的 loader:读失败只标 readError,
676
+ * 不记入分析错误。缺省 = 用 `loadModule`(旧行为)。
677
+ */
678
+ ambientLoadModule?: (spec: string, fromFile: string) => string | undefined;
679
+ /**
680
+ * ambient 绑定资格(autoBind / projectDir / node_modules)。
681
+ * 返回 false ⇒ 该侧车不会被 ambient 绑定 ⇒ 探测无意义 ⇒ 跳过
682
+ * (不读盘、不进指纹)。缺省 = 允许(旧行为:过近似,只过度失效)。
683
+ */
684
+ ambientAllowed?: (sidecarPath: string) => boolean;
685
+ };
585
686
  /**
586
687
  * All string module specs that analysis may resolve through loadModule.
587
- * Regex over-approximates (may hit comments) — extra dep fingerprint is safe
588
- * (more misses, never a stale hit).
688
+ *
689
+ * 正则**过近似**(可能命中注释里的假 import)**且**在两类形态上**欠近似**
690
+ * (仅副作用 import / 模板字符串 require)⇒ 正则集**并**AST 集(Bug 452):
691
+ * 并集只可能比现状**多**(more misses),不会比现状**少**(never a stale hit)。
589
692
  */
590
693
  declare function extractAllLoadSpecs(source: string): string[];
591
694
  /**
@@ -603,36 +706,16 @@ declare function sidecarSpecsOf(source: string): string[];
603
706
  * ambient 绑定其侧车,依赖侧车内容影响调用方报告——不进指纹则编辑后 memo
604
707
  * 陈旧命中(错诊断)。侧车 loadModule miss(无侧车文件)→ 不加任何条目。
605
708
  *
606
- * 注意:本扩展对 autoBind=false 与 /node_modules/ 均**不** gate(刻意过近似,
709
+ * 注意:本扩展对 autoBind=false 与 /node_modules/ 默认**不** gate(刻意过近似,
607
710
  * 只过度失效、绝不陈旧命中——安全方向);ambient 生效边界由
608
711
  * interface.ts 的 sidecarClosureFingerprint 负责,两者职责不同。
712
+ *
713
+ * Bug 1124:调用方(check.ts)可传 `opts.ambientAllowed`(ambient 绑定资格)
714
+ * 与 `opts.ambientLoadModule`(推测性探测 loader)——autoBind 关闭时该侧车
715
+ * 根本不会被绑定 ⇒ 不必探测;探测失败也**不得**升级成分析错误(门禁假红),
716
+ * 但仍须让本轮指纹不可信(readError ⇒ 禁 memo,错误轮与 miss 轮不共用键)。
609
717
  */
610
- declare function loadModuleDepsFingerprint(source: string, loadModule: (spec: string, fromFile: string) => string | undefined, fromFile: string): LoadDepsFingerprint;
611
-
612
- /**
613
- * 约束诊断:检查调用点实参是否满足函数的前置约束 / 参数 shape。
614
- * 输出可行动的建议,而不是 TS 式「类型不匹配」。
615
- */
616
-
617
- type Diagnostic = {
618
- severity: "error" | "warning" | "info";
619
- code: string;
620
- message: string;
621
- suggestion?: string;
622
- fn?: string;
623
- argIndex?: number;
624
- };
625
- /**
626
- * 检查实参是否满足「期望约束」。
627
- * expect: 相对参数 term 的 pred,例如 term > 0
628
- * arg: 实际实参 Abs
629
- */
630
- declare function checkArg(arg: Abs, expect: Pred | undefined, phi?: Phi): Diagnostic | undefined;
631
- /**
632
- * 对一次函数调用做诊断:实参 shape + 约束。
633
- */
634
- declare function checkCall(source: string, fnName: string, args: Abs[], phi?: Phi): Diagnostic[];
635
- declare function formatDiagnostics(diags: Diagnostic[]): string;
718
+ declare function loadModuleDepsFingerprint(source: string, loadModule: (spec: string, fromFile: string) => string | undefined, fromFile: string, opts?: LoadDepsFingerprintOpts): LoadDepsFingerprint;
636
719
 
637
720
  /**
638
721
  * check 报告面:数据模型 + 渲染/序列化。
@@ -652,9 +735,17 @@ type NudoSig = {
652
735
  paramTypes?: string[];
653
736
  /** 符号 Abs 本体 */
654
737
  abs: Abs;
655
- /** formatAbs 单行 */
738
+ /**
739
+ * 签名展示(**人类面口径**:shape 渲染)——与 `formatCheckReport` 的签名行
740
+ * **逐字同源**(Bug 413:机器面此前用 `formatAbs`,把 term / pred 段渲进
741
+ * 对外载荷,其中混着引擎内部计数器 id `len#N` ⇒ 载荷随参数列表位置漂移)。
742
+ */
656
743
  display: string;
657
- /** formatAbsMultiline */
744
+ /**
745
+ * 签名明细(多行;首行 = 函数名)——与人类面 `--verbose` 同源。
746
+ * term / pred 里的引擎内部计数器 id 换成**稳定名**(`len#2` → `len`)
747
+ * (Bug 413)。
748
+ */
658
749
  detail: string;
659
750
  conf: Confidence;
660
751
  /** throws 域展示(如 TypeError);省略 = 无 may-throw */
@@ -744,6 +835,17 @@ type CheckReport = {
744
835
  /**
745
836
  * `nudo check --json` 稳定契约(供 CI / Agent)。
746
837
  * 字段只增不改语义;Abs 以 formatAbs 字符串给出,不序列化内部 shape 图。
838
+ *
839
+ * ⚠ **Bug 413 的载荷语义变更**(v1 契约内的字段**取值口径**收紧):
840
+ * - `signatures[].display` 改为**人类面口径**(`formatShape`)⇒ 与 `nudo check`
841
+ * 的 signatures 行**逐字同源**(此前是 `formatAbs` 单行,两面不一致);
842
+ * - `signatures[].detail` / `signatures[].abs` 里的**引擎内部计数器 id**
843
+ * (`len#N` 一族)换成**稳定名**(`len#2` → `len`)⇒ 形状 / 谓词证据 /
844
+ * `#conf` / pathNote 全部保留,只有那个会随进程漂移的编号被抹平。
845
+ *
846
+ * 动机:内部计数器 id 的编号是**进程历史**的函数 ⇒ 同一个文件的载荷曾随
847
+ * 它在命令行参数列表中的位置漂移(`len#0` / `len#2` / `len#4`)⇒ 机器消费
848
+ * 方(CI diff / 快照 / 按文件比对)拿到的不是文件内容的函数。
747
849
  */
748
850
  type CheckJson = {
749
851
  version: 1;
@@ -874,6 +976,40 @@ declare function formatGitlabCodeQuality(r: CheckReport, opts?: {
874
976
  workspaceRoot?: string;
875
977
  }): GitlabCodeQualityIssue[];
876
978
 
979
+ /**
980
+ * 约束诊断:检查调用点实参是否满足函数的前置约束 / 参数 shape。
981
+ * 输出可行动的建议,而不是 TS 式「类型不匹配」。
982
+ *
983
+ * Bug 364:本模块此前**没有生产者**——`checkArg` / `checkCall` 是死码 ⇒
984
+ * 文档承诺的调用点验证面在产品里整体静默。`checkCallSite` 是接进产品
985
+ * 路径(`scan-literal-calls.ts` 的调用点扫描)的入口。
986
+ */
987
+
988
+ type Diagnostic = {
989
+ severity: "error" | "warning" | "info";
990
+ code: string;
991
+ message: string;
992
+ suggestion?: string;
993
+ fn?: string;
994
+ argIndex?: number;
995
+ };
996
+ /**
997
+ * 检查实参是否满足「期望约束」。
998
+ * expect: 相对参数 term 的 pred,例如 term > 0
999
+ * arg: 实际实参 Abs
1000
+ *
1001
+ * Bug 364:`expect` 的主题项是**参数位**的 term(通用化面里的 `A1`),
1002
+ * 而 `arg.pred` 相对**实参** term(`x`)⇒ 两者永不同一 ⇒ 任何非字面量
1003
+ * 实参都被判 `nudo:constraint-unproven`(假红)。⇒ 判定前把主题项
1004
+ * 对齐到实参自身的 term(`alignToArg`)。
1005
+ */
1006
+ declare function checkArg(arg: Abs, expect: Pred | undefined, phi?: Phi): Diagnostic | undefined;
1007
+ /**
1008
+ * 对一次函数调用做诊断:实参 shape + 约束。
1009
+ */
1010
+ declare function checkCall(source: string, fnName: string, args: Abs[], phi?: Phi): Diagnostic[];
1011
+ declare function formatDiagnostics(diags: Diagnostic[]): string;
1012
+
877
1013
  /**
878
1014
  * 投影/格式化层共享的 Abs 遍历预算(DESIGN-001)。
879
1015
  *
@@ -185,6 +185,17 @@ type Shape = {
185
185
  name?: string;
186
186
  paramTypes?: Abs[];
187
187
  returnType?: Abs;
188
+ /**
189
+ * Bug 399:逐位「可省略」标记(与 `params` 同下标,true = 该位有默认值 /
190
+ * 可省)。缺省 = 无标记(必选元数按名字后缀 `...` / `?` 判)。
191
+ *
192
+ * 为什么需要:默认形参(`f(a, b = 1)`)在形参表面上只是光秃秃的名字
193
+ * (`b`)⇒ 被计成必选元数 ⇒ `f = (x = 1) => x` 触发
194
+ * `nudo:assign-mismatch` 假红(JS 语义下 `(x = 1) => x` 的 `length` 是 0)。
195
+ *
196
+ * 与 `ctor` 同纪律:形态信息,不进指纹 / 展示串;`leq` 读它算必选元数。
197
+ */
198
+ optionalParams?: boolean[];
188
199
  /**
189
200
  * Dual-facet globals (Number/Array/…): callable AND carries static members.
190
201
  * `$get` reads these before falling back to Function.prototype names.
@@ -554,6 +565,11 @@ type AstEnv = {
554
565
  body: Node;
555
566
  async?: boolean;
556
567
  kind?: string;
568
+ /**
569
+ * Bug 399:逐位「可省略」标记(与 `params` 同下标,`true` = 该位有
570
+ * 默认值 / 带 `?` / 是 rest)⇒ 必选元数不再靠名字后缀猜。
571
+ */
572
+ optionalParams?: boolean[];
557
573
  }>;
558
574
  /** class 表(旁路,withVar 必须保留) */
559
575
  classes?: Map<string, unknown>;
@@ -617,12 +633,34 @@ type AbsFnImpl = {
617
633
  /** 声明时捕获的环境(闭包) */
618
634
  env?: AstEnv;
619
635
  kind?: string;
636
+ /**
637
+ * Bug 325:**函数种类**戳(async × generator 四象限)——原生
638
+ * `Object.prototype.toString.call(f)` 据此给标签(Function /
639
+ * AsyncFunction / GeneratorFunction / AsyncGeneratorFunction)。
640
+ *
641
+ * 与 `kind` 分开:`kind` 是**派发角色**维度("protoMethod" = 内建原型
642
+ * 方法值,抑制 $invokeInner 的回退再入),而类方法**同时**可能是
643
+ * generator(`class A { *m(){} }`)⇒ 两种语义不能共用一个字段。
644
+ */
645
+ fnKind?: "function" | "async" | "generator" | "async-generator";
620
646
  /**
621
647
  * Bug 9:原生 fn.length(首个默认值/rest 形参前的形参数)——静态已知时
622
648
  * 记录(宿主函数 v.length / 全 Identifier 形参的 AST),$len / $get 的
623
649
  * f.length 折 exact;未记录(默认值/嵌套默认模式不可判)→ 保守 number≥0。
624
650
  */
625
651
  length?: number;
652
+ /**
653
+ * Bug 399:逐位「可省略」标记(与 `params` **同下标**,`true` = 该位有
654
+ * 默认值 / 带 `?` / 是 rest ⇒ 调用方可省)。
655
+ *
656
+ * 为什么不能靠 `length` 代替:`length` 是「首个默认值/rest **前**的形参数」
657
+ * ⇒ `f(a, b = 1, c)` 的 length = 1,但 `c` 仍**必选**(TS 语义:可选参数
658
+ * 之后的参数仍必选)⇒ 必选元数 ≠ length。
659
+ *
660
+ * 消费侧:`leq.ts` 的 `fnRequiredArity`(先读本标记,缺省回退
661
+ * `requiredFnArity` 的名字后缀判据)。
662
+ */
663
+ optionalParams?: boolean[];
626
664
  /**
627
665
  * 调用时直接派发(mock withArgs 等),优先于 body。
628
666
  * 返回裸 Abs = 不抛;返回 AbsApplyResult 时 throws 面经 $call 统一路由,
@@ -758,6 +796,20 @@ type AbsModuleExports = {
758
796
  * 据此返回 default(= module.exports 值);缺省按命名空间对象口径。
759
797
  */
760
798
  cjsMain?: boolean;
799
+ /**
800
+ * CJS 互操作模块:ESM **默认导入**(`import fs from "node:fs"`)解析到
801
+ * **模块对象本身**(= 命名空间 Abs),而不是「没有 default ⇒ unknown」。
802
+ *
803
+ * Bug 282:env 模块(node:fs / node:path…)是 CJS 内建互操作模块——Node
804
+ * 的默认导出就是模块对象本身(具名导出挂在它上面)。env 表此前只有具名
805
+ * 导出、没有 default 槽 ⇒ 默认导入折 unknown ⇒ 导出函数全量降级
806
+ * unknown + **假** `nudo:unknown-inference` + 门禁**假绿**(同一模块的
807
+ * 命名空间导入却判红 ⇒ 同一种导入语义两种门禁结论)。
808
+ *
809
+ * 口径:只对**显式标记**的互操作模块生效——用户模块缺 default 仍是
810
+ * unknown(模块表有该 mod 但没有 default ⇒ 就是没有 default)。
811
+ */
812
+ interopDefault?: boolean;
761
813
  };
762
814
  /**
763
815
  * 命名空间 Abs(`import * as ns` / `export * as ns` / CJS require 绑定):
@@ -784,7 +836,8 @@ type RunTranspiledOptions = {
784
836
  mode?: "exec" | "analyze";
785
837
  /** @nudo:replace 注入值:varName → Abs */
786
838
  replacements?: Record<string, Abs>;
787
- /** @nudo:replace 匹配表:传给 transpile */
839
+ /** @nudo:replace 匹配表:传给 transpile(stmtStart/stmtEnd = **字符区间**
840
+ * `[start, end)`,非行号——Bug 166 起按 AST 节点身份定位) */
788
841
  replacementTargets?: Array<{
789
842
  target: string;
790
843
  varName: string;
@@ -793,7 +846,7 @@ type RunTranspiledOptions = {
793
846
  }>;
794
847
  /** @nudo:as 注入值:varName → Abs */
795
848
  asOverrides?: Record<string, Abs>;
796
- /** @nudo:as 语句范围表 */
849
+ /** @nudo:as 语句范围表(stmtStart/stmtEnd = **字符区间**,非行号) */
797
850
  asOverrideTargets?: Array<{
798
851
  varName: string;
799
852
  stmtStart: number;
@@ -808,6 +861,15 @@ type RunTranspiledOptions = {
808
861
  recordPositions?: boolean;
809
862
  /** 宽松全局(调用点发现 exec 采集:未声明全局调用保守 unknown 不中断) */
810
863
  lenientGlobals?: boolean;
864
+ /**
865
+ * **关闭** async 体的生成器路径(`$async` 同步路径)——安全网。
866
+ *
867
+ * Bug 1139:生成器模式下 `await` 的位置表与转译侧脱节 ⇒ `yield` 落进嵌套
868
+ * 箭头 ⇒ `new Function` SyntaxError ⇒ **整个模块**编译失败 ⇒ 全部导出
869
+ * 丢失 ⇒ L2 闸门**假绿**(exit 0)。本开关让求值引擎能在生成器模式编译
870
+ * 失败时**重试一次**(关闭生成器路径)⇒ 模块至少编译得出来 ⇒ 导出可见。
871
+ */
872
+ disableAsyncGen?: boolean;
811
873
  };
812
874
  /**
813
875
  * inject/modules **内容**指纹(memo 键)。对象身份对「每次新建同内容」
@@ -890,4 +952,4 @@ declare function callTranspiledExport(exports: Record<string, unknown>, name: st
890
952
  */
891
953
  declare function callTranspiledExportApply(exports: Record<string, unknown> | (() => Record<string, unknown>), name: string): (args: Abs[], thisVal?: Abs) => AbsApplyResult;
892
954
 
893
- export { $tryDigestSoft as $, type Abs as A, orphanMayThrowEffects as B, type Confidence as C, popMayThrowFrame as D, ERROR_FAMILY as E, pushMayThrowFrame as F, recordMayThrow as G, resetEvalFallbackStats as H, runWithMayThrowSession as I, setMayThrowCollector as J, throwAbsToKinds as K, type LiteralValue as L, type MayThrowEffect as M, throwsKindCovered as N, withEvalBudgetOverride as O, type PrimName as P, type HofCollectCtx as Q, type RelSource as R, type Shape as S, type Term as T, type HofSite as U, type RunTranspiledOptions as V, $assignRecord as W, $call as X, $callNamed as Y, $recordBinding as Z, type AbsApplyNoThrow as _, type Pred as a, markPureFn as a$, type AbsApplyNoThrowFn as a0, type AbsApplyResult as a1, type AbsApplyReturn as a2, type AbsFnImpl as a3, type AbsSigImpl as a4, type EvalAbsAssignRecord as a5, type EvalCallRecord as a6, type EvalFallback as a7, type EvalPosRecord as a8, type ImplicationOracle as a9, confJoin as aA, emptyPhi as aB, eq as aC, evalExprAbs as aD, ge as aE, geNum as aF, getEvalCallCollector as aG, getFnImpl as aH, getImplicationOracle as aI, gt as aJ, gtNum as aK, hostFnCtorFacet as aL, implies as aM, isAbsApplyResult as aN, isAbsVal as aO, isBigPrim as aP, isCjsMainRun as aQ, isExactLit as aR, isNumPrim as aS, isStrPrim as aT, le as aU, leNum as aV, lit as aW, litValue as aX, lt as aY, ltNum as aZ, makeAbsApplyResult as a_, type LitValueResult as aa, MAX_EVAL_CALL_DEPTH as ab, MAX_EVAL_TOTAL_CALLS as ac, RUNTIME_IMPORT_RE as ad, TYPEOF_NAMES as ae, type TranspiledCallResult as af, type TypeofName as ag, abs as ah, absFunction as ai, absOnly as aj, absToString as ak, and as al, anyAbs as am, anyVar as an, app as ao, assumeFinite as ap, attachFnImpl as aq, bigintLit as ar, bindImports as as, bindingsOf as at, bool as au, boolLit as av, callTranspiledExport as aw, callTranspiledExportApply as ax, callTranspiledExportFull as ay, collectAbsExports as az, type Phi as b, namespaceAbsOf as b0, ne as b1, negatePred as b2, never as b3, not as b4, noteEvalCallRecord as b5, noteEvalFallback as b6, num as b7, numLit as b8, numVar as b9, str as bA, strLit as bB, substPred as bC, termEquals as bD, termToString as bE, tryRunTranspiled as bF, unknown as bG, v as bH, $nodoPos as bI, getPosCollector as bJ, routeApplyThrows as bK, obj as ba, or as bb, pFalse as bc, pTrue as bd, phiAnd as be, predEquals as bf, predToString as bg, predVars as bh, primToTypeof as bi, ptypeof as bj, pureFnNameOf as bk, relationFingerprint as bl, relationFn as bm, resetEvalCallBudget as bn, runTranspiled as bo, runTranspiledOptionsMemoKey as bp, setEvalAssignCollector as bq, setEvalBindingSink as br, setEvalCallCollector as bs, setEvalFallbackCollector as bt, setImplicationOracle as bu, setPosCollector as bv, shapeOfTerm as bw, shapeOnlyFn as bx, shapeToString as by, simplifyTerm as bz, type AbsModuleExports as c, type AstEnv as d, $tryMarkSoft as e, $tryReleaseSoft as f, type EvalFallbackStats as g, absLit as h, absNumLit as i, absStrLit as j, allAbsStr as k, clearPureCallMemo as l, clearPureMemo as m, enterEvalCallBudgetSession as n, errorTypeAbs as o, exitEvalCallBudgetSession as p, filterDeclaredThrows as q, filterGateThrows as r, filterIgnoredThrows as s, flushMayThrowEffects as t, formatThrowsAbs as u, getEvalCallBudgetState as v, getEvalFallbackStats as w, getMayThrowCollector as x, isThrowsIgnored as y, mayThrowEffectsToAbs as z };
955
+ export { $tryDigestSoft as $, type Abs as A, orphanMayThrowEffects as B, type Confidence as C, popMayThrowFrame as D, ERROR_FAMILY as E, pushMayThrowFrame as F, recordMayThrow as G, resetEvalFallbackStats as H, runWithMayThrowSession as I, setMayThrowCollector as J, throwAbsToKinds as K, type LiteralValue as L, type MayThrowEffect as M, throwsKindCovered as N, withEvalBudgetOverride as O, type PrimName as P, type HofCollectCtx as Q, type RunTranspiledOptions as R, type Shape as S, type Term as T, type RelSource as U, type HofSite as V, $assignRecord as W, $call as X, $callNamed as Y, $recordBinding as Z, type AbsApplyNoThrow as _, type Pred as a, markPureFn as a$, type AbsApplyNoThrowFn as a0, type AbsApplyResult as a1, type AbsApplyReturn as a2, type AbsFnImpl as a3, type AbsSigImpl as a4, type EvalAbsAssignRecord as a5, type EvalCallRecord as a6, type EvalFallback as a7, type EvalPosRecord as a8, type ImplicationOracle as a9, confJoin as aA, emptyPhi as aB, eq as aC, evalExprAbs as aD, ge as aE, geNum as aF, getEvalCallCollector as aG, getFnImpl as aH, getImplicationOracle as aI, gt as aJ, gtNum as aK, hostFnCtorFacet as aL, implies as aM, isAbsApplyResult as aN, isAbsVal as aO, isBigPrim as aP, isCjsMainRun as aQ, isExactLit as aR, isNumPrim as aS, isStrPrim as aT, le as aU, leNum as aV, lit as aW, litValue as aX, lt as aY, ltNum as aZ, makeAbsApplyResult as a_, type LitValueResult as aa, MAX_EVAL_CALL_DEPTH as ab, MAX_EVAL_TOTAL_CALLS as ac, RUNTIME_IMPORT_RE as ad, TYPEOF_NAMES as ae, type TranspiledCallResult as af, type TypeofName as ag, abs as ah, absFunction as ai, absOnly as aj, absToString as ak, and as al, anyAbs as am, anyVar as an, app as ao, assumeFinite as ap, attachFnImpl as aq, bigintLit as ar, bindImports as as, bindingsOf as at, bool as au, boolLit as av, callTranspiledExport as aw, callTranspiledExportApply as ax, callTranspiledExportFull as ay, collectAbsExports as az, type Phi as b, namespaceAbsOf as b0, ne as b1, negatePred as b2, never as b3, not as b4, noteEvalCallRecord as b5, noteEvalFallback as b6, num as b7, numLit as b8, numVar as b9, str as bA, strLit as bB, substPred as bC, termEquals as bD, termToString as bE, tryRunTranspiled as bF, unknown as bG, v as bH, $nodoPos as bI, getPosCollector as bJ, routeApplyThrows as bK, obj as ba, or as bb, pFalse as bc, pTrue as bd, phiAnd as be, predEquals as bf, predToString as bg, predVars as bh, primToTypeof as bi, ptypeof as bj, pureFnNameOf as bk, relationFingerprint as bl, relationFn as bm, resetEvalCallBudget as bn, runTranspiled as bo, runTranspiledOptionsMemoKey as bp, setEvalAssignCollector as bq, setEvalBindingSink as br, setEvalCallCollector as bs, setEvalFallbackCollector as bt, setImplicationOracle as bu, setPosCollector as bv, shapeOfTerm as bw, shapeOnlyFn as bx, shapeToString as by, simplifyTerm as bz, type AbsModuleExports as c, type AstEnv as d, $tryMarkSoft as e, $tryReleaseSoft as f, type EvalFallbackStats as g, absLit as h, absNumLit as i, absStrLit as j, allAbsStr as k, clearPureCallMemo as l, clearPureMemo as m, enterEvalCallBudgetSession as n, errorTypeAbs as o, exitEvalCallBudgetSession as p, filterDeclaredThrows as q, filterGateThrows as r, filterIgnoredThrows as s, flushMayThrowEffects as t, formatThrowsAbs as u, getEvalCallBudgetState as v, getEvalFallbackStats as w, getMayThrowCollector as x, isThrowsIgnored as y, mayThrowEffectsToAbs as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudojs/core",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },