@nudojs/core 0.2.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.
- package/CHANGELOG.md +19 -0
- package/README.md +26 -0
- package/dist/index.d.ts +1601 -12
- package/dist/index.js +9657 -110
- package/package.json +18 -2
- package/src/__tests__/fn-sig-impl.test.ts +57 -0
- package/src/__tests__/ops-refined.test.ts +3 -1
- package/src/__tests__/ops.test.ts +8 -33
- package/src/__tests__/type-value.test.ts +106 -0
- package/src/algebra/__tests__/abs-native.test.ts +176 -0
- package/src/algebra/__tests__/arithmetic.test.ts +170 -0
- package/src/algebra/__tests__/ast-eval.test.ts +154 -0
- package/src/algebra/__tests__/bridge.test.ts +160 -0
- package/src/algebra/__tests__/call-budget.test.ts +117 -0
- package/src/algebra/__tests__/check-case-consistency.test.ts +69 -0
- package/src/algebra/__tests__/check-gold.test.ts +290 -0
- package/src/algebra/__tests__/check-json.test.ts +57 -0
- package/src/algebra/__tests__/check-mini-repo.test.ts +49 -0
- package/src/algebra/__tests__/check-real-commander.test.ts +43 -0
- package/src/algebra/__tests__/check-real-packages.test.ts +165 -0
- package/src/algebra/__tests__/check-recall-gold.test.ts +1024 -0
- package/src/algebra/__tests__/check-require-dep-memo.test.ts +45 -0
- package/src/algebra/__tests__/check-return-contract.test.ts +90 -0
- package/src/algebra/__tests__/check-shape-gold.test.ts +303 -0
- package/src/algebra/__tests__/check-source-memo.test.ts +204 -0
- package/src/algebra/__tests__/check.test.ts +69 -0
- package/src/algebra/__tests__/denote.test.ts +77 -0
- package/src/algebra/__tests__/diagnostics.test.ts +64 -0
- package/src/algebra/__tests__/differential.test.ts +124 -0
- package/src/algebra/__tests__/div-mod.test.ts +38 -0
- package/src/algebra/__tests__/example0.test.ts +103 -0
- package/src/algebra/__tests__/exec-analyze-throws.test.ts +60 -0
- package/src/algebra/__tests__/exec-async.test.ts +46 -0
- package/src/algebra/__tests__/exec-bpath.test.ts +193 -0
- package/src/algebra/__tests__/exec-class.test.ts +56 -0
- package/src/algebra/__tests__/exec-e2e.test.ts +97 -0
- package/src/algebra/__tests__/exec-generator.test.ts +53 -0
- package/src/algebra/__tests__/exec-inherit-default.test.ts +111 -0
- package/src/algebra/__tests__/exec-optional-nested.test.ts +87 -0
- package/src/algebra/__tests__/exec-rest.test.ts +55 -0
- package/src/algebra/__tests__/exec-spread-forof.test.ts +85 -0
- package/src/algebra/__tests__/exec-static-computed.test.ts +61 -0
- package/src/algebra/__tests__/exec-switch.test.ts +74 -0
- package/src/algebra/__tests__/exec-trycatch.test.ts +71 -0
- package/src/algebra/__tests__/fn-fp-memo.test.ts +166 -0
- package/src/algebra/__tests__/fn-fp-multidecl.test.ts +49 -0
- package/src/algebra/__tests__/format.test.ts +34 -0
- package/src/algebra/__tests__/generalize-memo.test.ts +285 -0
- package/src/algebra/__tests__/generalize.test.ts +113 -0
- package/src/algebra/__tests__/hash-source.test.ts +19 -0
- package/src/algebra/__tests__/hof.test.ts +80 -0
- package/src/algebra/__tests__/inlay.test.ts +30 -0
- package/src/algebra/__tests__/language.test.ts +77 -0
- package/src/algebra/__tests__/leq.test.ts +109 -0
- package/src/algebra/__tests__/load-deps-fp-memo.test.ts +132 -0
- package/src/algebra/__tests__/methods.test.ts +37 -0
- package/src/algebra/__tests__/node-types.test.ts +26 -0
- package/src/algebra/__tests__/nudo-constraints.ts +46 -0
- package/src/algebra/__tests__/objects.test.ts +117 -0
- package/src/algebra/__tests__/parse-source-cache.test.ts +42 -0
- package/src/algebra/__tests__/refine-import.test.ts +109 -0
- package/src/algebra/__tests__/stable-source-key-block.test.ts +23 -0
- package/src/algebra/__tests__/stable-source-key.test.ts +31 -0
- package/src/algebra/__tests__/surface.test.ts +41 -0
- package/src/algebra/__tests__/this-inherit.test.ts +130 -0
- package/src/algebra/abs-fn.ts +49 -0
- package/src/algebra/abs-modules.ts +139 -0
- package/src/algebra/abs.ts +206 -0
- package/src/algebra/arithmetic.ts +691 -0
- package/src/algebra/ast-eval.ts +1763 -0
- package/src/algebra/bridge.ts +350 -0
- package/src/algebra/builtins.ts +373 -0
- package/src/algebra/check-report.ts +150 -0
- package/src/algebra/check.ts +1867 -0
- package/src/algebra/constraint.ts +304 -0
- package/src/algebra/denote.ts +166 -0
- package/src/algebra/diagnostics.ts +210 -0
- package/src/algebra/exec/call.ts +29 -0
- package/src/algebra/exec/calls.ts +96 -0
- package/src/algebra/exec/class-registry.ts +29 -0
- package/src/algebra/exec/class.ts +329 -0
- package/src/algebra/exec/index.ts +6 -0
- package/src/algebra/exec/member-diag.ts +141 -0
- package/src/algebra/exec/run.ts +341 -0
- package/src/algebra/exec/runtime.ts +583 -0
- package/src/algebra/exec/transpile.ts +993 -0
- package/src/algebra/fn-fp.ts +294 -0
- package/src/algebra/format.ts +91 -0
- package/src/algebra/generalize.ts +776 -0
- package/src/algebra/hash-source.ts +27 -0
- package/src/algebra/index.ts +34 -0
- package/src/algebra/inlay.ts +198 -0
- package/src/algebra/language.ts +289 -0
- package/src/algebra/leak.ts +68 -0
- package/src/algebra/leq.ts +301 -0
- package/src/algebra/load-deps-fp.ts +97 -0
- package/src/algebra/methods.ts +128 -0
- package/src/algebra/objects.ts +251 -0
- package/src/algebra/parse-source.ts +64 -0
- package/src/algebra/phi.ts +42 -0
- package/src/algebra/pred.ts +395 -0
- package/src/algebra/refine.ts +227 -0
- package/src/algebra/stable-source-key.ts +81 -0
- package/src/algebra/surface.ts +206 -0
- package/src/algebra/template.ts +143 -0
- package/src/algebra/term.ts +119 -0
- package/src/environment.ts +5 -0
- package/src/index.ts +33 -0
- package/src/mock-helpers.ts +166 -0
- package/src/ops.ts +44 -63
- package/src/refinements/template-predicates.ts +11 -0
- package/src/refinements/template.ts +1 -3
- package/src/strip-types.ts +236 -0
- package/src/type-value.ts +153 -12
- package/src/refinements/index.ts +0 -2
package/src/type-value.ts
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import type { Node } from "@babel/types";
|
|
2
2
|
import type { Environment } from "./environment.ts";
|
|
3
|
+
// 注意:isTemplate 必须来自 template-predicates.ts(只含 `import type` 反向边)
|
|
4
|
+
// 而非 template.ts——后者运行时依赖本模块(T、typeValueToString),会构成环。
|
|
5
|
+
import { isTemplate } from "./refinements/template-predicates.ts";
|
|
3
6
|
|
|
4
|
-
// ---
|
|
7
|
+
// --- 评估 IR:不是类型系统本体,是 Abs 的外延投影格式 ---
|
|
5
8
|
|
|
6
|
-
export type LiteralValue = string | number | boolean | null | undefined;
|
|
9
|
+
export type LiteralValue = string | number | boolean | bigint | null | undefined;
|
|
10
|
+
|
|
11
|
+
// `thisVal` is the bound receiver when the signature is invoked as a method
|
|
12
|
+
// or through Function.prototype.call/apply (e.g. Object.prototype.toString
|
|
13
|
+
// brand computation needs it); direct calls leave it undefined.
|
|
14
|
+
export type SigImpl = (args: TypeValue[], thisVal?: TypeValue) => TypeValue | undefined;
|
|
15
|
+
|
|
16
|
+
export type FunctionSignature = {
|
|
17
|
+
paramTypes: TypeValue[];
|
|
18
|
+
returnType: TypeValue;
|
|
19
|
+
throwsType: TypeValue;
|
|
20
|
+
impl?: SigImpl;
|
|
21
|
+
};
|
|
7
22
|
|
|
8
23
|
export type Refinement = {
|
|
9
24
|
name: string;
|
|
@@ -83,6 +98,21 @@ export const T = {
|
|
|
83
98
|
base,
|
|
84
99
|
refinement,
|
|
85
100
|
}),
|
|
101
|
+
fnSig: (
|
|
102
|
+
paramTypes: TypeValue[],
|
|
103
|
+
returnType: TypeValue,
|
|
104
|
+
throwsType: TypeValue = { kind: "never" },
|
|
105
|
+
impl?: SigImpl,
|
|
106
|
+
): TypeValue => {
|
|
107
|
+
const dummy = {
|
|
108
|
+
kind: "function" as const,
|
|
109
|
+
params: paramTypes.map((_p, i) => `_arg${i}`),
|
|
110
|
+
body: { type: "BlockStatement", body: [], directives: [] } as unknown as Node,
|
|
111
|
+
closure: null as unknown as Environment,
|
|
112
|
+
};
|
|
113
|
+
(dummy as any)._signature = { paramTypes, returnType, throwsType, impl } satisfies FunctionSignature;
|
|
114
|
+
return dummy;
|
|
115
|
+
},
|
|
86
116
|
} as const;
|
|
87
117
|
|
|
88
118
|
// --- Helpers ---
|
|
@@ -112,6 +142,29 @@ export function typeValueEquals(a: TypeValue, b: TypeValue): boolean {
|
|
|
112
142
|
}
|
|
113
143
|
|
|
114
144
|
export function simplifyUnion(members: TypeValue[]): TypeValue {
|
|
145
|
+
// Fast path: empty or single element
|
|
146
|
+
if (members.length === 0) return T.never;
|
|
147
|
+
if (members.length === 1) return members[0].kind === "never" ? T.never : members[0];
|
|
148
|
+
|
|
149
|
+
// Fast path: two non-union elements, check equality first
|
|
150
|
+
if (members.length === 2) {
|
|
151
|
+
const a = members[0];
|
|
152
|
+
const b = members[1];
|
|
153
|
+
// Only use fast path if neither is a union (need flattening)
|
|
154
|
+
if (a.kind !== "union" && b.kind !== "union") {
|
|
155
|
+
if (a.kind === "never") return b.kind === "never" ? T.never : b;
|
|
156
|
+
if (b.kind === "never") return a;
|
|
157
|
+
if (typeValueEquals(a, b)) return a;
|
|
158
|
+
if (a.kind === "unknown" || b.kind === "unknown") return T.unknown;
|
|
159
|
+
// 吸收律:字面量被共存的 widening 基类型吸收(3 | number → number)
|
|
160
|
+
const aBase = absorbablePrimitiveBase(a);
|
|
161
|
+
if (aBase !== undefined && typeValueEquals(aBase, b)) return b;
|
|
162
|
+
const bBase = absorbablePrimitiveBase(b);
|
|
163
|
+
if (bBase !== undefined && typeValueEquals(bBase, a)) return a;
|
|
164
|
+
return { kind: "union", members: [a, b] };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
115
168
|
const flat: TypeValue[] = [];
|
|
116
169
|
for (const m of members) {
|
|
117
170
|
if (m.kind === "never") continue;
|
|
@@ -129,10 +182,38 @@ export function simplifyUnion(members: TypeValue[]): TypeValue {
|
|
|
129
182
|
}
|
|
130
183
|
}
|
|
131
184
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
185
|
+
// 吸收律:成员中存在某字面量/模板字面量的 widening 基类型(非字面量
|
|
186
|
+
// number/string/boolean/bigint)时,删去该字面量成员(3 | number → number、
|
|
187
|
+
// "a" | string → string)。不同基底(1 | "a")、纯字面量联合("a" | "b")、
|
|
188
|
+
// null/undefined 字面量不受影响;filter 保序,成员顺序稳定。
|
|
189
|
+
const primitives = deduped.filter((m) => m.kind === "primitive");
|
|
190
|
+
const absorbed =
|
|
191
|
+
primitives.length > 0
|
|
192
|
+
? deduped.filter((m) => {
|
|
193
|
+
const base = absorbablePrimitiveBase(m);
|
|
194
|
+
return base === undefined || !primitives.some((p) => typeValueEquals(p, base));
|
|
195
|
+
})
|
|
196
|
+
: deduped;
|
|
197
|
+
|
|
198
|
+
if (absorbed.length === 0) return T.never;
|
|
199
|
+
if (absorbed.length === 1) return absorbed[0];
|
|
200
|
+
if (absorbed.some((m) => m.kind === "unknown")) return T.unknown;
|
|
201
|
+
return { kind: "union", members: absorbed };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 吸收律辅助:返回 tv 可被吸收进的原语基类型(number/string/boolean/bigint)。
|
|
206
|
+
* 仅数字/字符串/布尔/bigint 字面量与模板字面量(refined over T.string)有值;
|
|
207
|
+
* null/undefined 字面量 widen 后仍是字面量、基类型原语与其余类型不参与吸收
|
|
208
|
+
* (基类型自身不能被自己吸收,否则纯原语联合 number | string 会被误删)。
|
|
209
|
+
*/
|
|
210
|
+
function absorbablePrimitiveBase(tv: TypeValue): TypeValue | undefined {
|
|
211
|
+
if (tv.kind === "literal") {
|
|
212
|
+
const widened = widenLiteral(tv);
|
|
213
|
+
return widened.kind === "primitive" ? widened : undefined;
|
|
214
|
+
}
|
|
215
|
+
if (isTemplate(tv)) return T.string;
|
|
216
|
+
return undefined;
|
|
136
217
|
}
|
|
137
218
|
|
|
138
219
|
export function widenLiteral(tv: TypeValue): TypeValue {
|
|
@@ -141,11 +222,34 @@ export function widenLiteral(tv: TypeValue): TypeValue {
|
|
|
141
222
|
if (typeof v === "number") return T.number;
|
|
142
223
|
if (typeof v === "string") return T.string;
|
|
143
224
|
if (typeof v === "boolean") return T.boolean;
|
|
225
|
+
// 吸收律要求 bigint 字面量能 widen 到 T.bigint
|
|
226
|
+
if (typeof v === "bigint") return T.bigint;
|
|
144
227
|
if (v === null) return T.null;
|
|
145
228
|
if (v === undefined) return T.undefined;
|
|
146
229
|
return T.unknown;
|
|
147
230
|
}
|
|
148
231
|
|
|
232
|
+
/**
|
|
233
|
+
* union 成员全部为同原语基底的字面量且数量 > maxLiterals 时塌缩为该基类型;
|
|
234
|
+
* 非 union、混合类型、或数量不超限的原样返回。
|
|
235
|
+
*
|
|
236
|
+
* 复用 simplifyUnion(内含吸收律与去重):先让「基类型已在场」的字面量被吸收
|
|
237
|
+
* (3 | number → number),再对剩余的纯字面量联合做阈值坍缩(1|2|…|20 → number)。
|
|
238
|
+
* 两步不冲突也不重复:吸收只删基类型已在场的字面量,阈值坍缩只处理无基类型
|
|
239
|
+
* 在场的纯字面量联合。
|
|
240
|
+
*/
|
|
241
|
+
export function collapseLiteralUnion(tv: TypeValue, maxLiterals: number): TypeValue {
|
|
242
|
+
if (tv.kind !== "union") return tv;
|
|
243
|
+
if (tv.members.length <= maxLiterals) return tv;
|
|
244
|
+
const simplified = simplifyUnion(tv.members);
|
|
245
|
+
if (simplified.kind !== "union") return simplified;
|
|
246
|
+
// 保守:成员中含非字面量(如显式 T.number 未吸收掉的异构成员)时不塌缩
|
|
247
|
+
if (!simplified.members.every((m) => m.kind === "literal")) return simplified;
|
|
248
|
+
const first = widenLiteral(simplified.members[0]);
|
|
249
|
+
if (!simplified.members.every((m) => typeValueEquals(widenLiteral(m), first))) return simplified;
|
|
250
|
+
return first;
|
|
251
|
+
}
|
|
252
|
+
|
|
149
253
|
export function isSubtypeOf(a: TypeValue, b: TypeValue): boolean {
|
|
150
254
|
if (b.kind === "unknown") return true;
|
|
151
255
|
if (a.kind === "never") return true;
|
|
@@ -284,6 +388,27 @@ export function mergeObjectProperties(
|
|
|
284
388
|
}
|
|
285
389
|
|
|
286
390
|
export function typeValueToString(tv: TypeValue): string {
|
|
391
|
+
// Self-referential structures (x.y = x surviving a clone) would recurse
|
|
392
|
+
// infinitely: a seen-set renders revisits as an ellipsis token.
|
|
393
|
+
return typeValueToStringInner(tv, new Set());
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function typeValueToStringInner(tv: TypeValue, seen: Set<object>, depth = 0): string {
|
|
397
|
+
// Path-scoped seen-set: a node renders "…" only while its own expansion
|
|
398
|
+
// is on the stack (a true cycle); shared singletons (T.number in two
|
|
399
|
+
// slots) still render in full. A depth cap bounds fixture-scale DAGs
|
|
400
|
+
// whose repeated shared substructure would otherwise explode the string.
|
|
401
|
+
if (depth > 48) return "…";
|
|
402
|
+
const recur = (inner: TypeValue): string => {
|
|
403
|
+
if (inner && typeof inner === "object") {
|
|
404
|
+
if (seen.has(inner)) return "…";
|
|
405
|
+
seen.add(inner);
|
|
406
|
+
const out = typeValueToStringInner(inner, seen, depth + 1);
|
|
407
|
+
seen.delete(inner);
|
|
408
|
+
return out;
|
|
409
|
+
}
|
|
410
|
+
return typeValueToStringInner(inner, seen, depth + 1);
|
|
411
|
+
};
|
|
287
412
|
switch (tv.kind) {
|
|
288
413
|
case "literal": {
|
|
289
414
|
const v = tv.value;
|
|
@@ -300,32 +425,37 @@ export function typeValueToString(tv: TypeValue): string {
|
|
|
300
425
|
const entries = Object.entries(tv.properties);
|
|
301
426
|
if (entries.length === 0) return "{}";
|
|
302
427
|
const inner = entries
|
|
303
|
-
.map(([k, v]) => `${k}: ${
|
|
428
|
+
.map(([k, v]) => `${k}: ${recur(v)}`)
|
|
304
429
|
.join(", ");
|
|
305
430
|
return `{ ${inner} }`;
|
|
306
431
|
}
|
|
307
432
|
case "array":
|
|
308
|
-
return `${
|
|
433
|
+
return `${recur(tv.element)}[]`;
|
|
309
434
|
case "tuple": {
|
|
310
|
-
const inner = tv.elements.map(
|
|
435
|
+
const inner = tv.elements.map(recur).join(", ");
|
|
311
436
|
return `[${inner}]`;
|
|
312
437
|
}
|
|
313
438
|
case "function": {
|
|
439
|
+
const sig = getFnSig(tv);
|
|
440
|
+
if (sig) {
|
|
441
|
+
const params = sig.paramTypes.map((p, i) => `${tv.params[i]}: ${recur(p)}`).join(", ");
|
|
442
|
+
return `(${params}) => ${recur(sig.returnType)}`;
|
|
443
|
+
}
|
|
314
444
|
const params = tv.params.join(", ");
|
|
315
445
|
return `(${params}) => ...`;
|
|
316
446
|
}
|
|
317
447
|
case "promise":
|
|
318
|
-
return `Promise<${
|
|
448
|
+
return `Promise<${recur(tv.value)}>`;
|
|
319
449
|
case "instance": {
|
|
320
450
|
const entries = Object.entries(tv.properties);
|
|
321
451
|
if (entries.length === 0) return tv.className;
|
|
322
452
|
const inner = entries
|
|
323
|
-
.map(([k, v]) => `${k}: ${
|
|
453
|
+
.map(([k, v]) => `${k}: ${recur(v)}`)
|
|
324
454
|
.join(", ");
|
|
325
455
|
return `${tv.className} { ${inner} }`;
|
|
326
456
|
}
|
|
327
457
|
case "union": {
|
|
328
|
-
return tv.members.map(
|
|
458
|
+
return tv.members.map(recur).join(" | ");
|
|
329
459
|
}
|
|
330
460
|
case "never":
|
|
331
461
|
return "never";
|
|
@@ -370,3 +500,14 @@ export function getPrimitiveTypeOf(tv: TypeValue): string | undefined {
|
|
|
370
500
|
export function getRefinedBase(tv: TypeValue): TypeValue {
|
|
371
501
|
return tv.kind === "refined" ? getRefinedBase(tv.base) : tv;
|
|
372
502
|
}
|
|
503
|
+
|
|
504
|
+
export function isFnSig(tv: TypeValue): boolean {
|
|
505
|
+
return tv.kind === "function" && "_signature" in tv;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export function getFnSig(tv: TypeValue): FunctionSignature | undefined {
|
|
509
|
+
if (tv.kind === "function" && "_signature" in tv) {
|
|
510
|
+
return (tv as any)._signature as FunctionSignature;
|
|
511
|
+
}
|
|
512
|
+
return undefined;
|
|
513
|
+
}
|
package/src/refinements/index.ts
DELETED