@nudojs/core 0.1.0 → 0.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.
Files changed (117) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +21 -0
  3. package/README.md +26 -0
  4. package/dist/index.d.ts +1633 -11
  5. package/dist/index.js +9965 -107
  6. package/package.json +28 -2
  7. package/src/__tests__/fn-sig-impl.test.ts +57 -0
  8. package/src/__tests__/ops-refined.test.ts +196 -0
  9. package/src/__tests__/ops.test.ts +8 -33
  10. package/src/__tests__/type-value-refined.test.ts +210 -0
  11. package/src/__tests__/type-value.test.ts +106 -0
  12. package/src/algebra/__tests__/abs-native.test.ts +176 -0
  13. package/src/algebra/__tests__/arithmetic.test.ts +170 -0
  14. package/src/algebra/__tests__/ast-eval.test.ts +154 -0
  15. package/src/algebra/__tests__/bridge.test.ts +160 -0
  16. package/src/algebra/__tests__/call-budget.test.ts +117 -0
  17. package/src/algebra/__tests__/check-case-consistency.test.ts +69 -0
  18. package/src/algebra/__tests__/check-gold.test.ts +290 -0
  19. package/src/algebra/__tests__/check-json.test.ts +57 -0
  20. package/src/algebra/__tests__/check-mini-repo.test.ts +49 -0
  21. package/src/algebra/__tests__/check-real-commander.test.ts +43 -0
  22. package/src/algebra/__tests__/check-real-packages.test.ts +165 -0
  23. package/src/algebra/__tests__/check-recall-gold.test.ts +1024 -0
  24. package/src/algebra/__tests__/check-require-dep-memo.test.ts +45 -0
  25. package/src/algebra/__tests__/check-return-contract.test.ts +90 -0
  26. package/src/algebra/__tests__/check-shape-gold.test.ts +303 -0
  27. package/src/algebra/__tests__/check-source-memo.test.ts +204 -0
  28. package/src/algebra/__tests__/check.test.ts +69 -0
  29. package/src/algebra/__tests__/denote.test.ts +77 -0
  30. package/src/algebra/__tests__/diagnostics.test.ts +64 -0
  31. package/src/algebra/__tests__/differential.test.ts +124 -0
  32. package/src/algebra/__tests__/div-mod.test.ts +38 -0
  33. package/src/algebra/__tests__/example0.test.ts +103 -0
  34. package/src/algebra/__tests__/exec-analyze-throws.test.ts +60 -0
  35. package/src/algebra/__tests__/exec-async.test.ts +46 -0
  36. package/src/algebra/__tests__/exec-bpath.test.ts +193 -0
  37. package/src/algebra/__tests__/exec-class.test.ts +56 -0
  38. package/src/algebra/__tests__/exec-e2e.test.ts +97 -0
  39. package/src/algebra/__tests__/exec-generator.test.ts +53 -0
  40. package/src/algebra/__tests__/exec-inherit-default.test.ts +111 -0
  41. package/src/algebra/__tests__/exec-optional-nested.test.ts +87 -0
  42. package/src/algebra/__tests__/exec-rest.test.ts +55 -0
  43. package/src/algebra/__tests__/exec-spread-forof.test.ts +85 -0
  44. package/src/algebra/__tests__/exec-static-computed.test.ts +61 -0
  45. package/src/algebra/__tests__/exec-switch.test.ts +74 -0
  46. package/src/algebra/__tests__/exec-trycatch.test.ts +71 -0
  47. package/src/algebra/__tests__/fn-fp-memo.test.ts +166 -0
  48. package/src/algebra/__tests__/fn-fp-multidecl.test.ts +49 -0
  49. package/src/algebra/__tests__/format.test.ts +34 -0
  50. package/src/algebra/__tests__/generalize-memo.test.ts +285 -0
  51. package/src/algebra/__tests__/generalize.test.ts +113 -0
  52. package/src/algebra/__tests__/hash-source.test.ts +19 -0
  53. package/src/algebra/__tests__/hof.test.ts +80 -0
  54. package/src/algebra/__tests__/inlay.test.ts +30 -0
  55. package/src/algebra/__tests__/language.test.ts +77 -0
  56. package/src/algebra/__tests__/leq.test.ts +109 -0
  57. package/src/algebra/__tests__/load-deps-fp-memo.test.ts +132 -0
  58. package/src/algebra/__tests__/methods.test.ts +37 -0
  59. package/src/algebra/__tests__/node-types.test.ts +26 -0
  60. package/src/algebra/__tests__/nudo-constraints.ts +46 -0
  61. package/src/algebra/__tests__/objects.test.ts +117 -0
  62. package/src/algebra/__tests__/parse-source-cache.test.ts +42 -0
  63. package/src/algebra/__tests__/refine-import.test.ts +109 -0
  64. package/src/algebra/__tests__/stable-source-key-block.test.ts +23 -0
  65. package/src/algebra/__tests__/stable-source-key.test.ts +31 -0
  66. package/src/algebra/__tests__/surface.test.ts +41 -0
  67. package/src/algebra/__tests__/this-inherit.test.ts +130 -0
  68. package/src/algebra/abs-fn.ts +49 -0
  69. package/src/algebra/abs-modules.ts +139 -0
  70. package/src/algebra/abs.ts +206 -0
  71. package/src/algebra/arithmetic.ts +691 -0
  72. package/src/algebra/ast-eval.ts +1763 -0
  73. package/src/algebra/bridge.ts +350 -0
  74. package/src/algebra/builtins.ts +373 -0
  75. package/src/algebra/check-report.ts +150 -0
  76. package/src/algebra/check.ts +1867 -0
  77. package/src/algebra/constraint.ts +304 -0
  78. package/src/algebra/denote.ts +166 -0
  79. package/src/algebra/diagnostics.ts +210 -0
  80. package/src/algebra/exec/call.ts +29 -0
  81. package/src/algebra/exec/calls.ts +96 -0
  82. package/src/algebra/exec/class-registry.ts +29 -0
  83. package/src/algebra/exec/class.ts +329 -0
  84. package/src/algebra/exec/index.ts +6 -0
  85. package/src/algebra/exec/member-diag.ts +141 -0
  86. package/src/algebra/exec/run.ts +341 -0
  87. package/src/algebra/exec/runtime.ts +583 -0
  88. package/src/algebra/exec/transpile.ts +993 -0
  89. package/src/algebra/fn-fp.ts +294 -0
  90. package/src/algebra/format.ts +91 -0
  91. package/src/algebra/generalize.ts +776 -0
  92. package/src/algebra/hash-source.ts +27 -0
  93. package/src/algebra/index.ts +34 -0
  94. package/src/algebra/inlay.ts +198 -0
  95. package/src/algebra/language.ts +289 -0
  96. package/src/algebra/leak.ts +68 -0
  97. package/src/algebra/leq.ts +301 -0
  98. package/src/algebra/load-deps-fp.ts +97 -0
  99. package/src/algebra/methods.ts +128 -0
  100. package/src/algebra/objects.ts +251 -0
  101. package/src/algebra/parse-source.ts +64 -0
  102. package/src/algebra/phi.ts +42 -0
  103. package/src/algebra/pred.ts +395 -0
  104. package/src/algebra/refine.ts +227 -0
  105. package/src/algebra/stable-source-key.ts +81 -0
  106. package/src/algebra/surface.ts +206 -0
  107. package/src/algebra/template.ts +143 -0
  108. package/src/algebra/term.ts +119 -0
  109. package/src/environment.ts +5 -0
  110. package/src/index.ts +52 -1
  111. package/src/mock-helpers.ts +166 -0
  112. package/src/ops.ts +106 -62
  113. package/src/refinements/range.ts +86 -0
  114. package/src/refinements/template-predicates.ts +11 -0
  115. package/src/refinements/template.ts +176 -0
  116. package/src/strip-types.ts +236 -0
  117. package/src/type-value.ts +193 -12
@@ -0,0 +1,251 @@
1
+ /**
2
+ * 结构层:对象槽位、spread、函数重载并。
3
+ * 纪律:积之和默认;optional 塌缩是显式损失;函数并保输入→输出相关性。
4
+ */
5
+
6
+ import type { Term } from "./term.ts";
7
+ import type { Pred } from "./pred.ts";
8
+ import { pTrue } from "./pred.ts";
9
+ import type { Abs, Shape, Confidence } from "./abs.ts";
10
+ import { abs, confJoin, litValue, unknown, never } from "./abs.ts";
11
+
12
+ export type Slot = { value: Abs; optional?: boolean; readonly?: boolean };
13
+
14
+ export type ObjShape = {
15
+ k: "obj";
16
+ slots: Record<string, Slot>;
17
+ index?: { key: Abs; value: Abs };
18
+ open?: boolean;
19
+ };
20
+
21
+ export function objOf(
22
+ slots: Record<string, Slot>,
23
+ opts?: { index?: { key: Abs; value: Abs }; open?: boolean },
24
+ ): Abs {
25
+ const shape: ObjShape = { k: "obj", slots };
26
+ if (opts?.index) shape.index = opts.index;
27
+ if (opts?.open) shape.open = true;
28
+ return { shape, conf: "exact" };
29
+ }
30
+
31
+ export function isObj(a: Abs): a is Abs & { shape: ObjShape } {
32
+ return a.shape.k === "obj";
33
+ }
34
+
35
+ /**
36
+ * spread:base ⊕ over(右侧覆盖,不是 join)
37
+ * 未出现在 over 的 key 保留 base;over 的 key 覆盖。
38
+ */
39
+ export function spread(base: Abs, over: Abs): Abs {
40
+ if (!isObj(base) && !isObj(over)) {
41
+ // 其中一侧 unknown:结果 open + 保留已知
42
+ if (isObj(over)) return { shape: { ...over.shape, open: true }, conf: confJoin(base.conf, over.conf) };
43
+ if (isObj(base)) return { shape: { ...base.shape, open: true }, conf: confJoin(base.conf, over.conf) };
44
+ return unknown;
45
+ }
46
+ if (!isObj(over)) {
47
+ // over 是 unknown:base 字段都可能被覆盖 → open
48
+ if (!isObj(base)) return unknown;
49
+ return {
50
+ shape: { ...base.shape, open: true },
51
+ conf: confJoin(base.conf, "partial"),
52
+ };
53
+ }
54
+ if (!isObj(base)) {
55
+ return { shape: { ...over.shape, open: true }, conf: confJoin(base.conf, over.conf) };
56
+ }
57
+
58
+ const slots: Record<string, Slot> = { ...base.shape.slots };
59
+ for (const [k, s] of Object.entries(over.shape.slots)) {
60
+ slots[k] = s;
61
+ }
62
+ // over 缺席的 key:若 over 是 open/有动态 key,则原 key 可能仍存在也可能被删
63
+ // JS spread 只覆盖 over 上出现的 key,缺席 key 保留 → 直接保留
64
+ const open = base.shape.open || over.shape.open || false;
65
+ const shape: ObjShape = { k: "obj", slots };
66
+ if (open) shape.open = true;
67
+ if (base.shape.index || over.shape.index) {
68
+ shape.index = over.shape.index ?? base.shape.index;
69
+ }
70
+ return { shape, conf: confJoin(base.conf, over.conf) };
71
+ }
72
+
73
+ /**
74
+ * 对象 join:默认积之和(sum),不自动折 optional。
75
+ * 同 key 集:槽位级 join(字面量并);异 key 集:保持 sum。
76
+ */
77
+ export function joinObjects(a: Abs, b: Abs): Abs {
78
+ if (a.shape.k === "never") return b;
79
+ if (b.shape.k === "never") return a;
80
+ if (!isObj(a) || !isObj(b)) {
81
+ // 跨 kind → sum(用 Shape sum)
82
+ return makeSum(a, b);
83
+ }
84
+
85
+ const ka = Object.keys(a.shape.slots).sort();
86
+ const kb = Object.keys(b.shape.slots).sort();
87
+ const sameKeys = ka.length === kb.length && ka.every((k, i) => k === kb[i]);
88
+
89
+ if (!sameKeys) {
90
+ // 异 key 集:保持 sum,绝不折 optional
91
+ return makeSum(a, b);
92
+ }
93
+
94
+ const slots: Record<string, Slot> = {};
95
+ let conf: Confidence = confJoin(a.conf, b.conf);
96
+ for (const k of ka) {
97
+ const sa = a.shape.slots[k]!;
98
+ const sb = b.shape.slots[k]!;
99
+ const optional = sa.optional || sb.optional;
100
+ const jv = joinValues(sa.value, sb.value);
101
+ conf = confJoin(conf, jv.conf);
102
+ slots[k] = { value: jv, optional };
103
+ }
104
+ return { shape: { k: "obj", slots }, conf };
105
+ }
106
+
107
+ /** 值级 join:字面量保留为… Phase A 对 prim 做 term 保留策略 */
108
+ export function joinValues(a: Abs, b: Abs): Abs {
109
+ if (a.shape.k === "never") return b;
110
+ if (b.shape.k === "never") return a;
111
+
112
+ const va = litValue(a);
113
+ const vb = litValue(b);
114
+ if (va !== undefined && va === vb) return a;
115
+
116
+ if (
117
+ a.shape.k === "prim" &&
118
+ b.shape.k === "prim" &&
119
+ a.shape.type === b.shape.type
120
+ ) {
121
+ // 双字面量:保留 term 为「丢失」,shape 仍 prim;置信度 path
122
+ // (完整 sum-of-literals 需要 Abs.sum members — Phase B 可扩)
123
+ if (va !== undefined && vb !== undefined) {
124
+ return abs(
125
+ a.shape,
126
+ undefined,
127
+ undefined,
128
+ confJoin(a.conf, "path"),
129
+ );
130
+ }
131
+ return abs(a.shape, undefined, undefined, confJoin(confJoin(a.conf, b.conf), "path"));
132
+ }
133
+
134
+ return makeSum(a, b);
135
+ }
136
+
137
+ export function makeSum(a: Abs, b: Abs): Abs {
138
+ const members = flattenSum([a, b]);
139
+ if (members.length === 1) return members[0]!;
140
+ return {
141
+ shape: { k: "sum", members },
142
+ conf: confJoin(a.conf, b.conf),
143
+ };
144
+ }
145
+
146
+ function flattenSum(xs: Abs[]): Abs[] {
147
+ const out: Abs[] = [];
148
+ for (const x of xs) {
149
+ if (x.shape.k === "sum") out.push(...x.shape.members);
150
+ else out.push(x);
151
+ }
152
+ // 简单去重(按 shape 粗等)
153
+ const seen = new Set<string>();
154
+ const deduped: Abs[] = [];
155
+ for (const x of out) {
156
+ const key = shapeKey(x);
157
+ if (seen.has(key)) continue;
158
+ seen.add(key);
159
+ deduped.push(x);
160
+ }
161
+ return deduped;
162
+ }
163
+
164
+ function shapeKey(a: Abs): string {
165
+ const s = a.shape;
166
+ if (s.k === "prim") return `prim:${s.type}`;
167
+ if (s.k === "never") return "never";
168
+ if (s.k === "any") return "any";
169
+ if (s.k === "unknown") return "unknown";
170
+ if (s.k === "obj") return `obj:${Object.keys(s.slots).sort().join(",")}`;
171
+ if (s.k === "fn") return `fn:${s.params.length}`;
172
+ if (s.k === "sum") return `sum:${s.members.length}`;
173
+ return "other";
174
+ }
175
+
176
+ /**
177
+ * 显式损失:sum-of-products → optional 槽(仅 emit/阈值)。
178
+ * 强制 #widened。
179
+ */
180
+ export function collapseToOptional(sum: Abs): Abs {
181
+ if (sum.shape.k !== "sum") {
182
+ if (isObj(sum)) return { ...sum, conf: confJoin(sum.conf, "widened") };
183
+ return sum;
184
+ }
185
+ const objs = sum.shape.members.filter(isObj);
186
+ if (objs.length === 0) {
187
+ return abs({ k: "unknown" }, undefined, undefined, "widened");
188
+ }
189
+ const allKeys = new Set<string>();
190
+ for (const o of objs) {
191
+ for (const k of Object.keys(o.shape.slots)) allKeys.add(k);
192
+ }
193
+ const slots: Record<string, Slot> = {};
194
+ for (const k of allKeys) {
195
+ const present = objs.filter((o) => k in o.shape.slots);
196
+ const values = present.map((o) => o.shape.slots[k]!.value);
197
+ const joined = values.reduce((acc, v) => joinValues(acc, v));
198
+ const optional = present.length < objs.length;
199
+ slots[k] = { value: joined, optional };
200
+ }
201
+ return { shape: { k: "obj", slots }, conf: "widened" };
202
+ }
203
+
204
+ // --- 函数重载并 ---
205
+
206
+ export type FnAbs = Abs & {
207
+ shape: {
208
+ k: "fn";
209
+ params: string[];
210
+ name?: string;
211
+ /** 外延参数类型(若已知) */
212
+ paramTypes?: Abs[];
213
+ /** 外延返回类型 */
214
+ returnType?: Abs;
215
+ };
216
+ };
217
+
218
+ export function fnOf(params: string[], name?: string): Abs {
219
+ const shape: Shape = { k: "fn", params };
220
+ if (name) (shape as { name?: string }).name = name;
221
+ return { shape, conf: "exact" };
222
+ }
223
+
224
+ /**
225
+ * 函数 join:签名并(重载),禁止 (A|C)→(B|D)。
226
+ */
227
+ export function joinFunctions(a: Abs, b: Abs): Abs {
228
+ const sa = a.shape;
229
+ const sb = b.shape;
230
+ if (sa.k !== "fn" || sb.k !== "fn") return makeSum(a, b);
231
+ const an = sa.name;
232
+ const bn = sb.name;
233
+ if (an && an === bn) {
234
+ if (
235
+ sa.params.length === sb.params.length &&
236
+ sa.params.every((p, i) => p === sb.params[i])
237
+ ) {
238
+ return a;
239
+ }
240
+ }
241
+ return makeSum(a, b);
242
+ }
243
+
244
+ /** 通用 join:分派到对象/函数/值 */
245
+ export function joinAbs(a: Abs, b: Abs): Abs {
246
+ if (a.shape.k === "never") return b;
247
+ if (b.shape.k === "never") return a;
248
+ if (isObj(a) && isObj(b)) return joinObjects(a, b);
249
+ if (a.shape.k === "fn" && b.shape.k === "fn") return joinFunctions(a, b);
250
+ return joinValues(a, b);
251
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * AST 源码解析入口(core 层)。
3
+ * 不依赖 @nudojs/parser,避免 core ↔ parser 包环。
4
+ * 与 parser.parse 同插件集 + 统一 TS 剥除。
5
+ *
6
+ * 进程内 LRU:同一 source 字符串只 parse 一次(check / generalize / eval 共享)。
7
+ */
8
+ import { parse as babelParse } from "@babel/parser";
9
+ import type { File } from "@babel/types";
10
+ import { stripTypes } from "../strip-types.ts";
11
+
12
+ /**
13
+ * 会话内 AST 缓存上限。key 是完整 source——碰撞安全(SameValueZero),
14
+ * 但每个条目都钉住一份源码文本,故 cap 必须远小于「随便缓存」:
15
+ * 16 × 1MB ≈ 16MB 源码 key 上界(File 本体另计)。
16
+ */
17
+ const MAX_AST_CACHE = 16;
18
+ /** Skip caching sources whose text alone would dominate session memory. */
19
+ const MAX_AST_SOURCE_CHARS = 1_000_000;
20
+ const astCache = new Map<string, File>();
21
+
22
+ export function resetParseSourceCache(): void {
23
+ astCache.clear();
24
+ }
25
+
26
+ export function getParseSourceCacheSize(): number {
27
+ return astCache.size;
28
+ }
29
+
30
+ function parseUncached(source: string, opts?: { errorRecovery?: boolean }): File {
31
+ const ast = babelParse(source, {
32
+ sourceType: "module",
33
+ plugins: ["typescript", "jsx"],
34
+ attachComment: true,
35
+ errorRecovery: opts?.errorRecovery === true,
36
+ });
37
+ return stripTypes(ast);
38
+ }
39
+
40
+ export function parseSource(
41
+ source: string,
42
+ opts?: { errorRecovery?: boolean },
43
+ ): File {
44
+ // errorRecovery 是兜底路径,不进缓存(可能产出不完整 AST)
45
+ if (opts?.errorRecovery === true) {
46
+ return parseUncached(source, opts);
47
+ }
48
+ if (source.length > MAX_AST_SOURCE_CHARS) {
49
+ return parseUncached(source, opts);
50
+ }
51
+ const hit = astCache.get(source);
52
+ if (hit !== undefined) {
53
+ astCache.delete(source);
54
+ astCache.set(source, hit);
55
+ return hit;
56
+ }
57
+ const ast = parseUncached(source, opts);
58
+ if (astCache.size >= MAX_AST_CACHE) {
59
+ const oldest = astCache.keys().next().value;
60
+ if (oldest !== undefined) astCache.delete(oldest);
61
+ }
62
+ astCache.set(source, ast);
63
+ return ast;
64
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 路径约束栈(Φ)。
3
+ *
4
+ * Φ 是当前控制流路径上的合取前提。代数运算(add/cmp/…)读取它做单调传播;
5
+ * evaluator 在 if 守卫处 push/pop。栈属于类型系统,不属于 host CLI。
6
+ */
7
+
8
+ import type { Phi } from "./pred.ts";
9
+ import { pTrue } from "./pred.ts";
10
+
11
+ let phiStack: Phi[] = [pTrue];
12
+
13
+ export function currentPhi(): Phi {
14
+ return phiStack[phiStack.length - 1] ?? pTrue;
15
+ }
16
+
17
+ export function pushPhi(p: Phi): void {
18
+ phiStack.push(p);
19
+ }
20
+
21
+ export function popPhi(): void {
22
+ if (phiStack.length > 1) phiStack.pop();
23
+ }
24
+
25
+ export function resetPhi(): void {
26
+ phiStack = [pTrue];
27
+ }
28
+
29
+ /** 在当前 Φ 上合取额外约束,body 结束后恢复 */
30
+ export function withPhiConstraint(extra: Phi, body: () => void): void {
31
+ pushPhi(extra);
32
+ try {
33
+ body();
34
+ } finally {
35
+ popPhi();
36
+ }
37
+ }
38
+
39
+ export function describePhi(): string {
40
+ const p = currentPhi();
41
+ return p.op === "true" ? "⊤" : "(phi)";
42
+ }