@nudojs/core 0.3.0 → 0.4.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 (123) hide show
  1. package/dist/chunk-N7E2A7IK.js +7216 -0
  2. package/dist/exec.d.ts +2 -0
  3. package/dist/exec.js +174 -0
  4. package/dist/index-DgyudAkw.d.ts +911 -0
  5. package/dist/index.d.ts +64 -710
  6. package/dist/index.js +3269 -8426
  7. package/package.json +18 -5
  8. package/CHANGELOG.md +0 -34
  9. package/src/__tests__/environment.test.ts +0 -48
  10. package/src/__tests__/fn-sig-impl.test.ts +0 -57
  11. package/src/__tests__/ops-refined.test.ts +0 -196
  12. package/src/__tests__/ops.test.ts +0 -84
  13. package/src/__tests__/type-value-phase2.test.ts +0 -117
  14. package/src/__tests__/type-value-phase3.test.ts +0 -94
  15. package/src/__tests__/type-value-refined.test.ts +0 -210
  16. package/src/__tests__/type-value.test.ts +0 -319
  17. package/src/algebra/__tests__/abs-native.test.ts +0 -176
  18. package/src/algebra/__tests__/arithmetic.test.ts +0 -170
  19. package/src/algebra/__tests__/ast-eval.test.ts +0 -154
  20. package/src/algebra/__tests__/bridge.test.ts +0 -160
  21. package/src/algebra/__tests__/call-budget.test.ts +0 -117
  22. package/src/algebra/__tests__/check-case-consistency.test.ts +0 -69
  23. package/src/algebra/__tests__/check-gold.test.ts +0 -290
  24. package/src/algebra/__tests__/check-json.test.ts +0 -57
  25. package/src/algebra/__tests__/check-mini-repo.test.ts +0 -49
  26. package/src/algebra/__tests__/check-real-commander.test.ts +0 -43
  27. package/src/algebra/__tests__/check-real-packages.test.ts +0 -165
  28. package/src/algebra/__tests__/check-recall-gold.test.ts +0 -1024
  29. package/src/algebra/__tests__/check-require-dep-memo.test.ts +0 -45
  30. package/src/algebra/__tests__/check-return-contract.test.ts +0 -90
  31. package/src/algebra/__tests__/check-shape-gold.test.ts +0 -303
  32. package/src/algebra/__tests__/check-source-memo.test.ts +0 -204
  33. package/src/algebra/__tests__/check.test.ts +0 -69
  34. package/src/algebra/__tests__/denote.test.ts +0 -77
  35. package/src/algebra/__tests__/diagnostics.test.ts +0 -64
  36. package/src/algebra/__tests__/differential.test.ts +0 -124
  37. package/src/algebra/__tests__/div-mod.test.ts +0 -38
  38. package/src/algebra/__tests__/example0.test.ts +0 -103
  39. package/src/algebra/__tests__/exec-analyze-throws.test.ts +0 -60
  40. package/src/algebra/__tests__/exec-async.test.ts +0 -46
  41. package/src/algebra/__tests__/exec-bpath.test.ts +0 -193
  42. package/src/algebra/__tests__/exec-class.test.ts +0 -56
  43. package/src/algebra/__tests__/exec-e2e.test.ts +0 -97
  44. package/src/algebra/__tests__/exec-generator.test.ts +0 -53
  45. package/src/algebra/__tests__/exec-inherit-default.test.ts +0 -111
  46. package/src/algebra/__tests__/exec-optional-nested.test.ts +0 -87
  47. package/src/algebra/__tests__/exec-rest.test.ts +0 -55
  48. package/src/algebra/__tests__/exec-spread-forof.test.ts +0 -85
  49. package/src/algebra/__tests__/exec-static-computed.test.ts +0 -61
  50. package/src/algebra/__tests__/exec-switch.test.ts +0 -74
  51. package/src/algebra/__tests__/exec-trycatch.test.ts +0 -71
  52. package/src/algebra/__tests__/fn-fp-memo.test.ts +0 -166
  53. package/src/algebra/__tests__/fn-fp-multidecl.test.ts +0 -49
  54. package/src/algebra/__tests__/format.test.ts +0 -34
  55. package/src/algebra/__tests__/generalize-memo.test.ts +0 -285
  56. package/src/algebra/__tests__/generalize.test.ts +0 -113
  57. package/src/algebra/__tests__/hash-source.test.ts +0 -19
  58. package/src/algebra/__tests__/hof.test.ts +0 -80
  59. package/src/algebra/__tests__/inlay.test.ts +0 -30
  60. package/src/algebra/__tests__/language.test.ts +0 -77
  61. package/src/algebra/__tests__/leq.test.ts +0 -109
  62. package/src/algebra/__tests__/load-deps-fp-memo.test.ts +0 -132
  63. package/src/algebra/__tests__/methods.test.ts +0 -37
  64. package/src/algebra/__tests__/node-types.test.ts +0 -26
  65. package/src/algebra/__tests__/nudo-constraints.ts +0 -46
  66. package/src/algebra/__tests__/objects.test.ts +0 -117
  67. package/src/algebra/__tests__/parse-source-cache.test.ts +0 -42
  68. package/src/algebra/__tests__/refine-import.test.ts +0 -109
  69. package/src/algebra/__tests__/stable-source-key-block.test.ts +0 -23
  70. package/src/algebra/__tests__/stable-source-key.test.ts +0 -31
  71. package/src/algebra/__tests__/surface.test.ts +0 -41
  72. package/src/algebra/__tests__/this-inherit.test.ts +0 -130
  73. package/src/algebra/abs-fn.ts +0 -49
  74. package/src/algebra/abs-modules.ts +0 -139
  75. package/src/algebra/abs.ts +0 -206
  76. package/src/algebra/arithmetic.ts +0 -691
  77. package/src/algebra/ast-eval.ts +0 -1763
  78. package/src/algebra/bridge.ts +0 -350
  79. package/src/algebra/builtins.ts +0 -373
  80. package/src/algebra/check-report.ts +0 -150
  81. package/src/algebra/check.ts +0 -1867
  82. package/src/algebra/constraint.ts +0 -304
  83. package/src/algebra/denote.ts +0 -166
  84. package/src/algebra/diagnostics.ts +0 -210
  85. package/src/algebra/exec/call.ts +0 -29
  86. package/src/algebra/exec/calls.ts +0 -96
  87. package/src/algebra/exec/class-registry.ts +0 -29
  88. package/src/algebra/exec/class.ts +0 -329
  89. package/src/algebra/exec/index.ts +0 -6
  90. package/src/algebra/exec/member-diag.ts +0 -141
  91. package/src/algebra/exec/run.ts +0 -341
  92. package/src/algebra/exec/runtime.ts +0 -583
  93. package/src/algebra/exec/transpile.ts +0 -993
  94. package/src/algebra/fn-fp.ts +0 -294
  95. package/src/algebra/format.ts +0 -91
  96. package/src/algebra/generalize.ts +0 -776
  97. package/src/algebra/hash-source.ts +0 -27
  98. package/src/algebra/index.ts +0 -34
  99. package/src/algebra/inlay.ts +0 -198
  100. package/src/algebra/language.ts +0 -289
  101. package/src/algebra/leak.ts +0 -68
  102. package/src/algebra/leq.ts +0 -301
  103. package/src/algebra/load-deps-fp.ts +0 -97
  104. package/src/algebra/methods.ts +0 -128
  105. package/src/algebra/objects.ts +0 -251
  106. package/src/algebra/parse-source.ts +0 -64
  107. package/src/algebra/phi.ts +0 -42
  108. package/src/algebra/pred.ts +0 -395
  109. package/src/algebra/refine.ts +0 -227
  110. package/src/algebra/stable-source-key.ts +0 -81
  111. package/src/algebra/surface.ts +0 -206
  112. package/src/algebra/template.ts +0 -143
  113. package/src/algebra/term.ts +0 -119
  114. package/src/environment.ts +0 -74
  115. package/src/index.ts +0 -73
  116. package/src/mock-helpers.ts +0 -166
  117. package/src/ops.ts +0 -191
  118. package/src/refinements/range.ts +0 -86
  119. package/src/refinements/template-predicates.ts +0 -11
  120. package/src/refinements/template.ts +0 -176
  121. package/src/strip-types.ts +0 -236
  122. package/src/type-value.ts +0 -513
  123. package/tsconfig.json +0 -8
@@ -1,166 +0,0 @@
1
- /**
2
- * Nudo Mock 帮助函数
3
- *
4
- * 提供类型安全的 mock 创建,替代 sinon 表达式
5
- */
6
-
7
- import { type TypeValue, T, typeValueEquals } from "./type-value.ts";
8
- import type { Environment } from "./environment.ts";
9
-
10
- export type MockHelper = {
11
- kind: "mock-helper";
12
- returnValue?: TypeValue;
13
- resolvedValue?: TypeValue;
14
- rejectedValue?: TypeValue;
15
- implementation?: (...args: TypeValue[]) => TypeValue;
16
- onFirstCallValue?: TypeValue;
17
- onSecondCallValue?: TypeValue;
18
- withArgsCases?: { args: TypeValue[]; returnValue: TypeValue }[];
19
- callsFakeImpl?: TypeValue;
20
- };
21
-
22
- /**
23
- * 创建一个 stub mock
24
- * 用法: @nudo:mock fetch = stub()
25
- */
26
- export function stub(): MockHelper {
27
- return { kind: "mock-helper" };
28
- }
29
-
30
- /**
31
- * 创建一个返回指定值的 stub
32
- * 用法: @nudo:mock fetch = stub().returns({ data: "test" })
33
- */
34
- stub.returns = function(value: TypeValue): MockHelper {
35
- return { kind: "mock-helper", returnValue: value };
36
- };
37
-
38
- /**
39
- * 创建一个返回 Promise 的 stub
40
- * 用法: @nudo:mock fetch = stub().resolves({ data: "test" })
41
- */
42
- stub.resolves = function(value: TypeValue): MockHelper {
43
- return { kind: "mock-helper", resolvedValue: value };
44
- };
45
-
46
- /**
47
- * 创建一个拒绝 Promise 的 stub
48
- * 用法: @nudo:mock fetch = stub().rejects(new Error("fail"))
49
- */
50
- stub.rejects = function(value: TypeValue): MockHelper {
51
- return { kind: "mock-helper", rejectedValue: value };
52
- };
53
-
54
- stub.onFirstCall = function(value: TypeValue): MockHelper {
55
- return { kind: "mock-helper", onFirstCallValue: value };
56
- };
57
-
58
- stub.onSecondCall = function(value: TypeValue): MockHelper {
59
- return { kind: "mock-helper", onSecondCallValue: value };
60
- };
61
-
62
- stub.withArgs = function(...args: TypeValue[]): MockHelper {
63
- return { kind: "mock-helper", withArgsCases: [{ args, returnValue: T.unknown }] };
64
- };
65
-
66
- stub.callsFake = function(fn: TypeValue): MockHelper {
67
- return { kind: "mock-helper", callsFakeImpl: fn };
68
- };
69
-
70
- /**
71
- * 创建一个 spy mock
72
- * 用法: @nudo:mock handler = spy()
73
- */
74
- export function spy(): MockHelper {
75
- return { kind: "mock-helper" };
76
- }
77
-
78
- spy.returns = function(value: TypeValue): MockHelper {
79
- return { kind: "mock-helper", returnValue: value };
80
- };
81
-
82
- /**
83
- * 创建一个 mock
84
- * 用法: @nudo:mock service = mock()
85
- */
86
- export function mock(): MockHelper {
87
- return { kind: "mock-helper" };
88
- }
89
-
90
- /**
91
- * withArgs 实参匹配(sinon 深比较的保守近似):
92
- * - 字面量声明要求实参为同值字面量(withArgs(21) 只匹配调用实参 literal 21);
93
- * - primitive 声明(T.number 等)接受同源字面量(21 是 number);
94
- * - 其余(unknown 声明等)不视为可证明匹配,走默认 stub 行为。
95
- */
96
- function mockArgMatches(declared: TypeValue, actual: TypeValue | undefined): boolean {
97
- if (actual === undefined) return false;
98
- if (typeValueEquals(declared, actual)) return true;
99
- if (declared.kind === "primitive" && actual.kind === "literal") {
100
- const t = typeof actual.value;
101
- return (
102
- (declared.type === "number" && t === "number") ||
103
- (declared.type === "string" && t === "string") ||
104
- (declared.type === "boolean" && t === "boolean") ||
105
- (declared.type === "bigint" && t === "bigint") ||
106
- (declared.type === "symbol" && t === "symbol")
107
- );
108
- }
109
- return false;
110
- }
111
-
112
- /**
113
- * 将 MockHelper 转换为 TypeValue
114
- */
115
- export function mockHelperToTypeValue(helper: MockHelper, env: Environment): TypeValue {
116
- // callsFake(fn)(sinon 语义):stub 的调用 = 以实参执行 fn。
117
- // 直接绑定 fn 本身,与 @nudo:mock f = (x) => ... 的箭头函数值绑定走同一机制
118
- // (evaluator callFunction 的参数绑定 + 函数体求值)。不能设 _directReturn ——
119
- // 那会把「fake 函数值」本身当调用结果传播,经 HOF 进一步污染下游。
120
- if (helper.callsFakeImpl) {
121
- if (helper.callsFakeImpl.kind === "function") {
122
- return helper.callsFakeImpl;
123
- }
124
- // 非函数 fake 无「以实参执行」语义可言,退化为直接返回该值
125
- const plain = T.fn(["...args"], { type: "BlockStatement", body: [] } as any, env);
126
- (plain as any)._directReturn = helper.callsFakeImpl;
127
- return plain;
128
- }
129
-
130
- let defaultReturn: TypeValue;
131
- if (helper.resolvedValue) {
132
- defaultReturn = T.promise(helper.resolvedValue);
133
- } else if (helper.rejectedValue) {
134
- defaultReturn = T.never;
135
- } else if (helper.returnValue) {
136
- defaultReturn = helper.returnValue;
137
- } else if (helper.onFirstCallValue) {
138
- defaultReturn = helper.onFirstCallValue;
139
- } else {
140
- defaultReturn = T.unknown;
141
- }
142
-
143
- // withArgs 分派(sinon 语义):实参匹配的链返回其 returnValue,未命中走默认
144
- // stub 行为。经 fnSig impl 在调用时拿实参判定,优先于任何固定返回值。
145
- if (helper.withArgsCases?.length) {
146
- const cases = helper.withArgsCases;
147
- return T.fnSig(
148
- cases[0].args.map(() => T.unknown),
149
- T.union(...cases.map((c) => c.returnValue), defaultReturn),
150
- T.never,
151
- (args) => {
152
- for (const c of cases) {
153
- if (c.args.every((a, i) => mockArgMatches(a, args[i]))) {
154
- return c.returnValue;
155
- }
156
- }
157
- return defaultReturn;
158
- },
159
- );
160
- }
161
-
162
- const body = { type: "BlockStatement", body: [] } as any;
163
- const fn = T.fn(["...args"], body, env);
164
- (fn as any)._directReturn = defaultReturn;
165
- return fn;
166
- }
package/src/ops.ts DELETED
@@ -1,191 +0,0 @@
1
- /**
2
- * 残差 IR 兜底(不是类型运算真理源)。
3
- *
4
- * 真理在 algebra:算术/比较/相等/typeof/!/−/字符串词法序/nullish 均走 Abs。
5
- * 这里只保留:
6
- * - add:代数拒绝时的混合 `+`
7
- * - 比较/相等:代数无法判定时的保守 boolean / 字面量折叠
8
- * - dispatchMethod/Property:宿主 refined 扩展(startsWith、length…)
9
- */
10
- import { type TypeValue, type LiteralValue, T, isSubtypeOf } from "./type-value.ts";
11
- import { concatTemplates, isTemplate } from "./refinements/template.ts";
12
-
13
- function bothLiteral(
14
- l: TypeValue,
15
- r: TypeValue,
16
- ): { lv: LiteralValue; rv: LiteralValue } | null {
17
- if (l.kind === "literal" && r.kind === "literal") {
18
- return { lv: l.value, rv: r.value };
19
- }
20
- return null;
21
- }
22
-
23
- function isNullishLiteral(tv: TypeValue): boolean {
24
- return tv.kind === "literal" && (tv.value === null || tv.value === undefined);
25
- }
26
-
27
- function definitelyNotNullish(tv: TypeValue): boolean {
28
- switch (tv.kind) {
29
- case "literal":
30
- return tv.value !== null && tv.value !== undefined;
31
- case "primitive":
32
- case "object":
33
- case "array":
34
- case "tuple":
35
- case "function":
36
- case "instance":
37
- case "promise":
38
- return true;
39
- case "refined":
40
- return definitelyNotNullish(tv.base);
41
- case "union":
42
- return tv.members.every(definitelyNotNullish);
43
- default:
44
- return false;
45
- }
46
- }
47
-
48
- export const Ops = {
49
- add(left: TypeValue, right: TypeValue): TypeValue {
50
- const lit = bothLiteral(left, right);
51
- if (lit) {
52
- return T.literal((lit.lv as any) + (lit.rv as any));
53
- }
54
- const leftIsString = isSubtypeOf(left, T.string) || isTemplate(left);
55
- const rightIsString = isSubtypeOf(right, T.string) || isTemplate(right);
56
- if (leftIsString || rightIsString) {
57
- const hasStructure =
58
- (left.kind === "literal" && typeof left.value === "string") ||
59
- (right.kind === "literal" && typeof right.value === "string") ||
60
- isTemplate(left) || isTemplate(right);
61
- if (hasStructure) {
62
- return concatTemplates(left, right);
63
- }
64
- return T.string;
65
- }
66
- if (isSubtypeOf(left, T.number) && isSubtypeOf(right, T.number)) {
67
- return T.number;
68
- }
69
- return T.union(T.number, T.string);
70
- },
71
-
72
- strictEq(left: TypeValue, right: TypeValue): TypeValue {
73
- const lit = bothLiteral(left, right);
74
- if (lit) return T.literal(lit.lv === lit.rv);
75
- if ((isNullishLiteral(right) && definitelyNotNullish(left)) ||
76
- (isNullishLiteral(left) && definitelyNotNullish(right))) {
77
- return T.literal(false);
78
- }
79
- return T.boolean;
80
- },
81
-
82
- strictNeq(left: TypeValue, right: TypeValue): TypeValue {
83
- const lit = bothLiteral(left, right);
84
- if (lit) return T.literal(lit.lv !== lit.rv);
85
- if ((isNullishLiteral(right) && definitelyNotNullish(left)) ||
86
- (isNullishLiteral(left) && definitelyNotNullish(right))) {
87
- return T.literal(true);
88
- }
89
- return T.boolean;
90
- },
91
-
92
- gt(left: TypeValue, right: TypeValue): TypeValue {
93
- const lit = bothLiteral(left, right);
94
- if (lit) return T.literal((lit.lv as any) > (lit.rv as any));
95
- return T.boolean;
96
- },
97
-
98
- lt(left: TypeValue, right: TypeValue): TypeValue {
99
- const lit = bothLiteral(left, right);
100
- if (lit) return T.literal((lit.lv as any) < (lit.rv as any));
101
- return T.boolean;
102
- },
103
-
104
- gte(left: TypeValue, right: TypeValue): TypeValue {
105
- const lit = bothLiteral(left, right);
106
- if (lit) return T.literal((lit.lv as any) >= (lit.rv as any));
107
- return T.boolean;
108
- },
109
-
110
- lte(left: TypeValue, right: TypeValue): TypeValue {
111
- const lit = bothLiteral(left, right);
112
- if (lit) return T.literal((lit.lv as any) <= (lit.rv as any));
113
- return T.boolean;
114
- },
115
-
116
- not(operand: TypeValue): TypeValue {
117
- if (operand.kind === "literal") return T.literal(!operand.value);
118
- return T.boolean;
119
- },
120
- } as const;
121
-
122
- const binaryOpMap: Record<string, (l: TypeValue, r: TypeValue) => TypeValue> = {
123
- "+": Ops.add,
124
- "===": Ops.strictEq,
125
- "!==": Ops.strictNeq,
126
- ">": Ops.gt,
127
- "<": Ops.lt,
128
- ">=": Ops.gte,
129
- "<=": Ops.lte,
130
- };
131
-
132
- export function applyBinaryOp(
133
- op: string,
134
- left: TypeValue,
135
- right: TypeValue,
136
- ): TypeValue {
137
- const fn = binaryOpMap[op];
138
- if (!fn) return T.unknown;
139
- return fn(left, right);
140
- }
141
-
142
- export function dispatchBinaryOp(
143
- op: string,
144
- left: TypeValue,
145
- right: TypeValue,
146
- ): TypeValue {
147
- if (left.kind === "refined" && left.refinement.ops?.[op]) {
148
- const result = left.refinement.ops[op](left, right);
149
- if (result !== undefined) return result;
150
- }
151
- if (right.kind === "refined" && right.refinement.ops?.[op]) {
152
- const result = right.refinement.ops[op](right, left);
153
- if (result !== undefined) return result;
154
- }
155
-
156
- const baseLeft = left.kind === "refined" ? left.base : left;
157
- const baseRight = right.kind === "refined" ? right.base : right;
158
- if (baseLeft !== left || baseRight !== right) {
159
- return dispatchBinaryOp(op, baseLeft, baseRight);
160
- }
161
- return applyBinaryOp(op, left, right);
162
- }
163
-
164
- export function dispatchMethod(
165
- receiver: TypeValue,
166
- name: string,
167
- args: TypeValue[],
168
- ): TypeValue | undefined {
169
- if (receiver.kind === "refined" && receiver.refinement.methods?.[name]) {
170
- const result = receiver.refinement.methods[name](receiver, args);
171
- if (result !== undefined) return result;
172
- }
173
- if (receiver.kind === "refined") {
174
- return dispatchMethod(receiver.base, name, args);
175
- }
176
- return undefined;
177
- }
178
-
179
- export function dispatchProperty(
180
- receiver: TypeValue,
181
- name: string,
182
- ): TypeValue | undefined {
183
- if (receiver.kind === "refined" && receiver.refinement.properties?.[name]) {
184
- const result = receiver.refinement.properties[name](receiver);
185
- if (result !== undefined) return result;
186
- }
187
- if (receiver.kind === "refined") {
188
- return dispatchProperty(receiver.base, name);
189
- }
190
- return undefined;
191
- }
@@ -1,86 +0,0 @@
1
- import { type TypeValue, type Refinement, T } from "../type-value.ts";
2
-
3
- export type RangeMeta = {
4
- min?: number;
5
- max?: number;
6
- integer?: boolean;
7
- };
8
-
9
- function formatRangeName(meta: RangeMeta): string {
10
- const parts: string[] = [];
11
- if (meta.integer) parts.push("integer");
12
- else parts.push("number");
13
-
14
- const constraints: string[] = [];
15
- if (meta.min != null) constraints.push(`>= ${meta.min}`);
16
- if (meta.max != null) constraints.push(`<= ${meta.max}`);
17
- if (constraints.length > 0) parts.push(`(${constraints.join(", ")})`);
18
-
19
- return parts.join(" ");
20
- }
21
-
22
- function createRangeRefinement(meta: RangeMeta): Refinement {
23
- return {
24
- name: formatRangeName(meta),
25
- meta: { ...meta },
26
- check(value: unknown) {
27
- if (typeof value !== "number") return false;
28
- if (meta.integer && !Number.isInteger(value)) return false;
29
- if (meta.min != null && value < meta.min) return false;
30
- if (meta.max != null && value > meta.max) return false;
31
- return true;
32
- },
33
- ops: {
34
- ">="(self: TypeValue, other: TypeValue) {
35
- const m = getRangeMeta(self);
36
- if (!m || other.kind !== "literal" || typeof other.value !== "number") return undefined;
37
- if (m.min != null && m.min >= other.value) return T.literal(true);
38
- if (m.max != null && m.max < other.value) return T.literal(false);
39
- return undefined;
40
- },
41
- ">"(self: TypeValue, other: TypeValue) {
42
- const m = getRangeMeta(self);
43
- if (!m || other.kind !== "literal" || typeof other.value !== "number") return undefined;
44
- if (m.min != null && m.min > other.value) return T.literal(true);
45
- if (m.max != null && m.max <= other.value) return T.literal(false);
46
- return undefined;
47
- },
48
- "<="(self: TypeValue, other: TypeValue) {
49
- const m = getRangeMeta(self);
50
- if (!m || other.kind !== "literal" || typeof other.value !== "number") return undefined;
51
- if (m.max != null && m.max <= other.value) return T.literal(true);
52
- if (m.min != null && m.min > other.value) return T.literal(false);
53
- return undefined;
54
- },
55
- "<"(self: TypeValue, other: TypeValue) {
56
- const m = getRangeMeta(self);
57
- if (!m || other.kind !== "literal" || typeof other.value !== "number") return undefined;
58
- if (m.max != null && m.max < other.value) return T.literal(true);
59
- if (m.min != null && m.min >= other.value) return T.literal(false);
60
- return undefined;
61
- },
62
- },
63
- };
64
- }
65
-
66
- export function createRange(meta: RangeMeta): TypeValue {
67
- if (meta.min != null && meta.max != null && meta.min === meta.max) {
68
- return T.literal(meta.min);
69
- }
70
- return T.refine(T.number, createRangeRefinement(meta));
71
- }
72
-
73
- export function isRange(tv: TypeValue): boolean {
74
- if (tv.kind !== "refined") return false;
75
- const m = tv.refinement.meta;
76
- return m.min !== undefined || m.max !== undefined || m.integer !== undefined;
77
- }
78
-
79
- export function getRangeMeta(tv: TypeValue): RangeMeta | undefined {
80
- if (tv.kind !== "refined") return undefined;
81
- const m = tv.refinement.meta;
82
- if (m.min !== undefined || m.max !== undefined || m.integer !== undefined) {
83
- return m as RangeMeta;
84
- }
85
- return undefined;
86
- }
@@ -1,11 +0,0 @@
1
- import type { TypeValue } from "../type-value.ts";
2
-
3
- /**
4
- * 模板字面量谓词,独立于 template.ts 以断开运行时循环引用:
5
- * type-value.ts(联合吸收律)与 template.ts 都依赖本模块,而本模块对
6
- * type-value.ts 只有 `import type` 边(编译后消失),运行时依赖保持单向
7
- * type-value.ts / template.ts -> template-predicates.ts。
8
- */
9
- export function isTemplate(tv: TypeValue): boolean {
10
- return tv.kind === "refined" && Array.isArray(tv.refinement.meta.parts);
11
- }
@@ -1,176 +0,0 @@
1
- import { type TypeValue, type Refinement, T, typeValueToString } from "../type-value.ts";
2
- import { createRange } from "./range.ts";
3
-
4
- export function getKnownPrefix(parts: TypeValue[]): string {
5
- let prefix = "";
6
- for (const p of parts) {
7
- if (p.kind === "literal" && typeof p.value === "string") {
8
- prefix += p.value;
9
- } else {
10
- break;
11
- }
12
- }
13
- return prefix;
14
- }
15
-
16
- export function getKnownSuffix(parts: TypeValue[]): string {
17
- let suffix = "";
18
- for (let i = parts.length - 1; i >= 0; i--) {
19
- const p = parts[i];
20
- if (p.kind === "literal" && typeof p.value === "string") {
21
- suffix = p.value + suffix;
22
- } else {
23
- break;
24
- }
25
- }
26
- return suffix;
27
- }
28
-
29
- function getFixedLength(parts: TypeValue[]): number {
30
- let len = 0;
31
- for (const p of parts) {
32
- if (p.kind === "literal" && typeof p.value === "string") {
33
- len += p.value.length;
34
- }
35
- }
36
- return len;
37
- }
38
-
39
- function getAllFixedText(parts: TypeValue[]): string {
40
- return parts
41
- .filter((p): p is TypeValue & { kind: "literal" } => p.kind === "literal" && typeof p.value === "string")
42
- .map((p) => p.value as string)
43
- .join("");
44
- }
45
-
46
- function formatTemplateName(parts: TypeValue[]): string {
47
- const inner = parts
48
- .map((p) => (p.kind === "literal" && typeof p.value === "string" ? p.value : `\${${typeValueToString(p)}}`))
49
- .join("");
50
- return `\`${inner}\``;
51
- }
52
-
53
- function normalizeParts(parts: TypeValue[]): TypeValue[] {
54
- const result: TypeValue[] = [];
55
- for (const p of parts) {
56
- const last = result[result.length - 1];
57
- if (
58
- last?.kind === "literal" && typeof last.value === "string" &&
59
- p.kind === "literal" && typeof p.value === "string"
60
- ) {
61
- result[result.length - 1] = T.literal(last.value + p.value);
62
- } else if (
63
- last?.kind === "primitive" && last.type === "string" &&
64
- p.kind === "primitive" && p.type === "string"
65
- ) {
66
- // T.string + T.string collapses to T.string
67
- } else {
68
- result.push(p);
69
- }
70
- }
71
- return result;
72
- }
73
-
74
- function createTemplateRefinement(parts: TypeValue[]): Refinement {
75
- return {
76
- name: formatTemplateName(parts),
77
- meta: { parts },
78
- check(value: unknown) {
79
- if (typeof value !== "string") return false;
80
- return matchesTemplate(value, parts);
81
- },
82
- ops: {
83
- "+"(self: TypeValue, other: TypeValue) {
84
- return concatTemplates(self, other);
85
- },
86
- },
87
- methods: {
88
- startsWith(_self: TypeValue, args: TypeValue[]) {
89
- const arg = args[0];
90
- if (arg?.kind !== "literal" || typeof arg.value !== "string") return undefined;
91
- const prefix = getKnownPrefix((_self as any).refinement.meta.parts as TypeValue[]);
92
- const search = arg.value;
93
- if (prefix.length >= search.length) {
94
- return T.literal(prefix.startsWith(search));
95
- }
96
- if (search.startsWith(prefix)) return undefined;
97
- return T.literal(false);
98
- },
99
- endsWith(_self: TypeValue, args: TypeValue[]) {
100
- const arg = args[0];
101
- if (arg?.kind !== "literal" || typeof arg.value !== "string") return undefined;
102
- const suffix = getKnownSuffix((_self as any).refinement.meta.parts as TypeValue[]);
103
- const search = arg.value;
104
- if (suffix.length >= search.length) {
105
- return T.literal(suffix.endsWith(search));
106
- }
107
- if (search.endsWith(suffix)) return undefined;
108
- return T.literal(false);
109
- },
110
- includes(_self: TypeValue, args: TypeValue[]) {
111
- const arg = args[0];
112
- if (arg?.kind !== "literal" || typeof arg.value !== "string") return undefined;
113
- const fixed = getAllFixedText((_self as any).refinement.meta.parts as TypeValue[]);
114
- if (fixed.includes(arg.value)) return T.literal(true);
115
- return undefined;
116
- },
117
- },
118
- properties: {
119
- length(_self: TypeValue) {
120
- const parts = (_self as any).refinement.meta.parts as TypeValue[];
121
- const hasAbstract = parts.some((p) => p.kind !== "literal");
122
- if (!hasAbstract) return undefined;
123
- const minLen = getFixedLength(parts);
124
- return createRange({ min: minLen });
125
- },
126
- },
127
- };
128
- }
129
-
130
- function matchesTemplate(value: string, parts: TypeValue[]): boolean {
131
- let pos = 0;
132
- for (let i = 0; i < parts.length; i++) {
133
- const p = parts[i];
134
- if (p.kind === "literal" && typeof p.value === "string") {
135
- if (!value.startsWith(p.value, pos)) return false;
136
- pos += p.value.length;
137
- } else {
138
- if (i === parts.length - 1) return true;
139
- const next = parts[i + 1];
140
- if (next?.kind === "literal" && typeof next.value === "string") {
141
- const idx = value.indexOf(next.value, pos);
142
- if (idx === -1) return false;
143
- pos = idx;
144
- } else {
145
- return true;
146
- }
147
- }
148
- }
149
- return pos === value.length;
150
- }
151
-
152
- export function createTemplate(parts: TypeValue[]): TypeValue {
153
- const normalized = normalizeParts(parts);
154
- if (normalized.length === 1 && normalized[0].kind === "literal") {
155
- return normalized[0];
156
- }
157
- if (normalized.length === 1 && normalized[0].kind === "primitive" && normalized[0].type === "string") {
158
- return T.string;
159
- }
160
- return T.refine(T.string, createTemplateRefinement(normalized));
161
- }
162
-
163
- export { isTemplate } from "./template-predicates.ts";
164
-
165
- export function getTemplateParts(tv: TypeValue): TypeValue[] | undefined {
166
- if (tv.kind === "refined" && Array.isArray(tv.refinement.meta.parts)) {
167
- return tv.refinement.meta.parts as TypeValue[];
168
- }
169
- return undefined;
170
- }
171
-
172
- export function concatTemplates(left: TypeValue, right: TypeValue): TypeValue {
173
- const leftParts = getTemplateParts(left) ?? [left];
174
- const rightParts = getTemplateParts(right) ?? [right];
175
- return createTemplate([...leftParts, ...rightParts]);
176
- }