@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,117 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { checkSource } from "../check.ts";
3
- import {
4
- analyzeFn,
5
- evalProgramAbs,
6
- resetAbsCallBudget,
7
- MAX_CALL_DEPTH,
8
- } from "../ast-eval.ts";
9
- import { pTrue } from "../pred.ts";
10
- import { num, unknown } from "../abs.ts";
11
- import type { Abs } from "../abs.ts";
12
-
13
- const FAC = `
14
- function fac(n) {
15
- if (n <= 1) return 1;
16
- return n * fac(n - 1);
17
- }
18
- `;
19
-
20
- const FIB = `
21
- function fib(n) {
22
- if (n <= 1) return n;
23
- return fib(n - 1) + fib(n - 2);
24
- }
25
- `;
26
-
27
- const MUTUAL = `
28
- function isEven(n) {
29
- if (n === 0) return true;
30
- return isOdd(n - 1);
31
- }
32
- function isOdd(n) {
33
- if (n === 0) return false;
34
- return isEven(n - 1);
35
- }
36
- `;
37
-
38
- describe("Abs call budget (recursion guard)", () => {
39
- it("analyzeFn on factorial does not stack-overflow", () => {
40
- resetAbsCallBudget();
41
- const r = analyzeFn(FAC, "fac", [num()], pTrue);
42
- expect(r).toBeDefined();
43
- expect(r.shape.k === "unknown" || r.shape.k === "prim" || r.shape.k === "never").toBe(true);
44
- });
45
-
46
- it("analyzeFn on fib does not stack-overflow", () => {
47
- resetAbsCallBudget();
48
- const r = analyzeFn(FIB, "fib", [num()], pTrue);
49
- expect(r).toBeDefined();
50
- });
51
-
52
- it("mutual recursion does not stack-overflow", () => {
53
- resetAbsCallBudget();
54
- const r = analyzeFn(MUTUAL, "isEven", [num()], pTrue);
55
- expect(r).toBeDefined();
56
- });
57
-
58
- it("evalProgramAbs with top-level recursive call does not stack-overflow", () => {
59
- resetAbsCallBudget();
60
- const { last } = evalProgramAbs(`
61
- function count(n) {
62
- if (n <= 0) return 0;
63
- return 1 + count(n - 1);
64
- }
65
- const x = count(5);
66
- `);
67
- expect(last).toBeDefined();
68
- });
69
-
70
- it("concrete base-case recursion still evaluates", () => {
71
- // 调用深度在 64 内:count(5) 应给出字面量结果而非 opaque
72
- resetAbsCallBudget();
73
- const lit5: Abs = {
74
- shape: { k: "prim", type: "number" },
75
- term: { op: "lit", value: 5 },
76
- conf: "exact",
77
- };
78
- const r = analyzeFn(
79
- `
80
- function count(n) {
81
- if (n <= 0) return 0;
82
- return 1 + count(n - 1);
83
- }
84
- `,
85
- "count",
86
- [lit5],
87
- pTrue,
88
- );
89
- // 5 层展开应收敛为字面量 5(或至少 number)
90
- expect(r.shape.k === "prim" || r.shape.k === "never").toBe(true);
91
- if (r.term && r.term.op === "lit") {
92
- expect(r.term.value).toBe(5);
93
- }
94
- });
95
-
96
- it("checkSource completes on factorial with structured diagnostics", () => {
97
- const report = checkSource("/tmp/fac.js", FAC, pTrue, {});
98
- expect(report).toBeDefined();
99
- // 不得崩溃;递归截断记 warning
100
- const codes = report.issues.map((i) => i.code);
101
- expect(codes).toContain("nudo:recursion-truncated");
102
- expect(report.issues.every((i) => i.severity !== undefined)).toBe(true);
103
- });
104
-
105
- it("depth budget constant is aligned with TypeValue evaluator", () => {
106
- expect(MAX_CALL_DEPTH).toBe(64);
107
- });
108
-
109
- it("truncated result uses opaque conf, not partial-any", () => {
110
- resetAbsCallBudget();
111
- const r = analyzeFn(FAC, "fac", [num()], pTrue);
112
- // 截断后应为 unknown+opaque,或仍能算出的 prim;绝不能是 exact 的假结果
113
- if (r.shape.k === "unknown") {
114
- expect(r.conf === "opaque" || r.conf === "partial" || r.conf === "widened").toBe(true);
115
- }
116
- });
117
- });
@@ -1,69 +0,0 @@
1
- /**
2
- * case ⊄ refine → nudo:case-inconsistency
3
- * case 是契约的见证,不是另一套前置来源。
4
- */
5
- import { describe, it, expect } from "vitest";
6
- import { checkSource, pTrue } from "../index.ts";
7
- import { withStdImport, stdOpts } from "./nudo-constraints.ts";
8
-
9
- function issuesOf(src: string) {
10
- return checkSource("/t/case.js", withStdImport(src), pTrue, stdOpts);
11
- }
12
-
13
- describe("case vs refine", () => {
14
- it("ok: case 实参满足契约", () => {
15
- const r = issuesOf(`
16
- /**
17
- * @nudo:refine x positive
18
- * @nudo:case "ok" (5)
19
- */
20
- function needsPositive(x) {
21
- return x;
22
- }
23
- `);
24
- expect(r.issues.filter((i) => i.code === "nudo:case-inconsistency")).toEqual([]);
25
- });
26
-
27
- it("error: case 实参 ⊭ refine", () => {
28
- const r = issuesOf(`
29
- /**
30
- * @nudo:refine x positive
31
- * @nudo:case "neg" (-1)
32
- */
33
- function needsPositive(x) {
34
- return x;
35
- }
36
- `);
37
- const err = r.issues.find((i) => i.code === "nudo:case-inconsistency");
38
- expect(err).toBeDefined();
39
- expect(err!.severity).toBe("error");
40
- expect(err!.expected).toContain(">");
41
- expect(err!.message).toContain("neg");
42
- });
43
-
44
- it("error: percent 上界违例", () => {
45
- const r = issuesOf(`
46
- /**
47
- * @nudo:refine n percent
48
- * @nudo:case "big" (150)
49
- */
50
- function pct(n) {
51
- return n;
52
- }
53
- `);
54
- expect(r.ok).toBe(false);
55
- expect(r.issues.some((i) => i.code === "nudo:case-inconsistency")).toBe(true);
56
- });
57
-
58
- it("ok: 无 refine 的 case 不报", () => {
59
- const r = issuesOf(`
60
- /**
61
- * @nudo:case "any" (-1)
62
- */
63
- function id(x) {
64
- return x;
65
- }
66
- `);
67
- expect(r.issues.filter((i) => i.code === "nudo:case-inconsistency")).toEqual([]);
68
- });
69
- });
@@ -1,290 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { checkSource, pTrue } from "../index.ts";
3
- import { withStdImport, stdOpts } from "./nudo-constraints.ts";
4
-
5
- /**
6
- * nudo check 金标:多形态 JS 片段上的门禁行为。
7
- * 每条:source + 期望 ok / 期望出现的 issue code。
8
- */
9
-
10
- type Gold = {
11
- name: string;
12
- source: string;
13
- expectOk: boolean;
14
- expectCode?: string;
15
- };
16
-
17
- const golds: Gold[] = [
18
- {
19
- name: "valid positive call",
20
- source: `
21
- /**
22
- * @nudo:refine x positive
23
- */
24
- function needsPositive(x) {
25
- if (x > 0) return x;
26
- return 0;
27
- }
28
- const r = needsPositive(5);
29
- `,
30
- expectOk: true,
31
- },
32
- {
33
- name: "negative call violates x>0",
34
- source: `
35
- /**
36
- * @nudo:refine x positive
37
- */
38
- function needsPositive(x) {
39
- if (x > 0) return x;
40
- return 0;
41
- }
42
- const r = needsPositive(-1);
43
- `,
44
- expectOk: false,
45
- expectCode: "nudo:constraint-violated",
46
- },
47
- {
48
- name: "range guard lo is clamp not violation",
49
- source: `
50
- function clampId(id) {
51
- if (id < 1) return 1;
52
- if (id > 9999) return 9999;
53
- return id;
54
- }
55
- clampId(0);
56
- `,
57
- // `id < 1` 是回退守卫,不作为调用前置
58
- expectOk: true,
59
- },
60
- {
61
- name: "range guard valid mid",
62
- source: `
63
- function clampId(id) {
64
- if (id < 1) return 1;
65
- if (id > 9999) return 9999;
66
- return id;
67
- }
68
- clampId(50);
69
- `,
70
- expectOk: true,
71
- },
72
- {
73
- name: "pure arithmetic no constraints",
74
- source: `
75
- function add(a, b) { return a + b; }
76
- const r = add(1, 2);
77
- `,
78
- expectOk: true,
79
- },
80
- {
81
- name: "ESM export function still listed",
82
- source: `
83
- export function scale(x) { return x + 1; }
84
- `,
85
- expectOk: true,
86
- },
87
- {
88
- name: "async function listed",
89
- source: `
90
- export async function load(id) { return id + 1; }
91
- `,
92
- expectOk: true,
93
- },
94
- {
95
- name: "class constructor listed",
96
- source: `
97
- class Counter {
98
- constructor(n) { this.n = n; }
99
- get() { return this.n; }
100
- }
101
- export function main() { return new Counter(1).get(); }
102
- `,
103
- expectOk: true,
104
- },
105
- // --- 真阳性:必须报 ---
106
- {
107
- name: "zero violates x>0",
108
- source: `
109
- /**
110
- * @nudo:refine x positive
111
- */
112
- function needsPositive(x) {
113
- if (x > 0) return x;
114
- return 0;
115
- }
116
- needsPositive(0);
117
- `,
118
- expectOk: false,
119
- expectCode: "nudo:constraint-violated",
120
- },
121
- {
122
- name: "unary negative call",
123
- source: `
124
- /**
125
- * @nudo:refine x positive
126
- */
127
- function needsPositive(x) {
128
- if (x > 0) return x;
129
- return 0;
130
- }
131
- needsPositive(-3);
132
- `,
133
- expectOk: false,
134
- expectCode: "nudo:constraint-violated",
135
- },
136
- {
137
- name: "x>=1 rejects 0",
138
- source: `
139
- /**
140
- * @nudo:refine i atLeast1
141
- */
142
- function idx(i) {
143
- if (i >= 1) return i;
144
- return 1;
145
- }
146
- idx(0);
147
- `,
148
- expectOk: false,
149
- expectCode: "nudo:constraint-violated",
150
- },
151
- {
152
- name: "upper bound x<10 rejects 10",
153
- source: `
154
- /**
155
- * @nudo:refine n small
156
- */
157
- function small(n) {
158
- if (n < 10) return n;
159
- return 9;
160
- }
161
- small(10);
162
- `,
163
- expectOk: false,
164
- expectCode: "nudo:constraint-violated",
165
- },
166
- // --- 真阴性:不得误报(clamp / 无前置) ---
167
- {
168
- name: "clamp negative input is not violation",
169
- source: `
170
- function clamp(n, lo, hi) {
171
- if (n < lo) return lo;
172
- if (n > hi) return hi;
173
- return n;
174
- }
175
- clamp(-5, 0, 100);
176
- `,
177
- expectOk: true,
178
- },
179
- {
180
- name: "no guard no constraint",
181
- source: `
182
- function double(n) { return n * 2; }
183
- double(-1);
184
- `,
185
- expectOk: true,
186
- },
187
- {
188
- name: "equality guard is not numeric precondition",
189
- source: `
190
- function onlyZero(x) {
191
- if (x === 0) return 0;
192
- return 1;
193
- }
194
- onlyZero(5);
195
- `,
196
- expectOk: true,
197
- },
198
- {
199
- name: "min boundary valid",
200
- source: `
201
- function needsPositive(x) {
202
- if (x > 0) return x;
203
- return 0;
204
- }
205
- needsPositive(1);
206
- `,
207
- expectOk: true,
208
- },
209
- // --- 结构 ---
210
- {
211
- name: "arrow function constraint",
212
- source: `
213
- /**
214
- * @nudo:refine x positive
215
- */
216
- const needsPositive = (x) => {
217
- if (x > 0) return x;
218
- return 0;
219
- };
220
- needsPositive(-2);
221
- `,
222
- expectOk: false,
223
- expectCode: "nudo:constraint-violated",
224
- },
225
- {
226
- name: "export default function",
227
- source: `
228
- /**
229
- * @nudo:refine x positive
230
- */
231
- export default function needsPositive(x) {
232
- if (x > 0) return x;
233
- return 0;
234
- }
235
- needsPositive(-1);
236
- `,
237
- expectOk: false,
238
- expectCode: "nudo:constraint-violated",
239
- },
240
- {
241
- name: "both bounds mid valid",
242
- source: `
243
- /**
244
- * @nudo:refine n percent
245
- */
246
- function pct(n) {
247
- if (n >= 0 && n <= 100) return n;
248
- return 0;
249
- }
250
- pct(50);
251
- `,
252
- expectOk: true,
253
- },
254
- {
255
- name: "both bounds high invalid",
256
- source: `
257
- /**
258
- * @nudo:refine n percent
259
- */
260
- function pct(n) {
261
- if (n >= 0 && n <= 100) return n;
262
- return 0;
263
- }
264
- pct(150);
265
- `,
266
- expectOk: false,
267
- expectCode: "nudo:constraint-violated",
268
- },
269
- ];
270
-
271
- describe("nudo check gold standards", () => {
272
- for (const g of golds) {
273
- it(g.name, () => {
274
- const report = checkSource("gold.js", withStdImport(g.source), pTrue, stdOpts);
275
- expect(report.ok, formatIssues(report)).toBe(g.expectOk);
276
- if (g.expectCode) {
277
- expect(
278
- report.issues.some((i) => i.code === g.expectCode),
279
- formatIssues(report),
280
- ).toBe(true);
281
- }
282
- // 每个 case 至少能列出函数或明确无函数
283
- expect(Array.isArray(report.signatures)).toBe(true);
284
- });
285
- }
286
- });
287
-
288
- function formatIssues(r: { issues: Array<{ severity: string; code: string; message: string }> }): string {
289
- return r.issues.map((i) => `${i.severity} ${i.code}: ${i.message}`).join("; ") || "(none)";
290
- }
@@ -1,57 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { checkSource, serializeCheckJson, pTrue } from "../index.ts";
3
- import { withStdImport, stdOpts } from "./nudo-constraints.ts";
4
-
5
- describe("CheckJson contract v1", () => {
6
- const src = `
7
- /**
8
- * @nudo:refine x positive
9
- */
10
- function needsPositive(x) {
11
- if (x > 0) return x;
12
- return 0;
13
- }
14
- needsPositive(-1);
15
- `;
16
-
17
- it("has stable top-level fields", () => {
18
- const j = serializeCheckJson(checkSource("c.js", withStdImport(src), pTrue, stdOpts));
19
- expect(j.version).toBe(1);
20
- expect(j.file).toBe("c.js");
21
- expect(j.ok).toBe(false);
22
- expect(j.summary).toMatchObject({
23
- errors: expect.any(Number),
24
- warnings: expect.any(Number),
25
- infos: expect.any(Number),
26
- functions: expect.any(Number),
27
- });
28
- expect(Array.isArray(j.signatures)).toBe(true);
29
- expect(Array.isArray(j.issues)).toBe(true);
30
- });
31
-
32
- it("signatures carry abs display + detail", () => {
33
- const j = serializeCheckJson(checkSource("c.js", withStdImport(src), pTrue, stdOpts));
34
- const sig = j.signatures.find((s) => s.name === "needsPositive");
35
- expect(sig).toBeDefined();
36
- expect(sig!.params).toEqual(["x"]);
37
- expect(sig!.abs).toContain("#");
38
- expect(typeof sig!.conf).toBe("string");
39
- });
40
-
41
- it("issues carry actual/expected for violations", () => {
42
- const j = serializeCheckJson(checkSource("c.js", withStdImport(src), pTrue, stdOpts));
43
- const err = j.issues.find((i) => i.code === "nudo:constraint-violated");
44
- expect(err).toBeDefined();
45
- expect(err!.actual).toBeDefined();
46
- expect(err!.expected).toBeDefined();
47
- expect(err!.line).toBeGreaterThan(0);
48
- });
49
-
50
- it("ok file has ok:true and empty error issues", () => {
51
- const j = serializeCheckJson(
52
- checkSource("ok.js", `function f(x){ return x+1; }\nf(1);\n`, pTrue, stdOpts),
53
- );
54
- expect(j.ok).toBe(true);
55
- expect(j.issues.filter((i) => i.severity === "error")).toEqual([]);
56
- });
57
- });
@@ -1,49 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { readFileSync } from "node:fs";
3
- import { resolve, dirname } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { checkSource, pTrue } from "../index.ts";
6
- import { withStdImport, stdOpts } from "./nudo-constraints.ts";
7
-
8
- const root = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../../");
9
- const mini = (f: string) => readFileSync(resolve(root, "docs/examples/mini-repo", f), "utf8");
10
-
11
- /**
12
- * mini-repo 人工金标:文件级 check 期望。
13
- * 这是「替换 tsc」的 recall 基线——新增违例模式时先补这里。
14
- */
15
- describe("mini-repo check gold", () => {
16
- it("validators.js: no false positives", () => {
17
- const r = checkSource("validators.js", mini("validators.js"));
18
- expect(r.ok, r.issues.map((i) => i.message).join("; ")).toBe(true);
19
- expect(r.signatures.map((f) => f.name)).toContain("isPositive");
20
- expect(r.signatures.map((f) => f.name)).toContain("clamp");
21
- });
22
-
23
- it("store.js: class methods listed", () => {
24
- const r = checkSource("store.js", mini("store.js"));
25
- expect(r.ok).toBe(true);
26
- });
27
-
28
- it("user-service.js: ok (no literal violating calls)", () => {
29
- const r = checkSource("user-service.js", mini("user-service.js"));
30
- expect(r.ok, r.issues.map((i) => `${i.severity} ${i.message}`).join("; ")).toBe(true);
31
- });
32
-
33
- it("inline violating snippet still caught (TP recall)", () => {
34
- // isPositive 是谓词(无 if-return-param 前置);真正门禁用 refine
35
- const src = `
36
- /**
37
- * @nudo:refine x positive
38
- */
39
- function needsPositive(x) {
40
- if (x > 0) return x;
41
- return 0;
42
- }
43
- needsPositive(-1);
44
- `;
45
- const r = checkSource("tp.js", withStdImport(src), pTrue, stdOpts);
46
- expect(r.ok).toBe(false);
47
- expect(r.issues.some((i) => i.code === "nudo:constraint-violated")).toBe(true);
48
- });
49
- });
@@ -1,43 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { readFileSync, existsSync, readdirSync } from "node:fs";
3
- import { join, dirname, resolve } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { checkSource } from "../index.ts";
6
-
7
- /**
8
- * 真实包精度门禁:commander(devDep)上不得出现任何 error 级误报。
9
- * 包不存在时跳过(非 monorepo 环境)。
10
- */
11
-
12
- const root = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../..");
13
- const commanderLib = join(root, "node_modules/commander/lib");
14
-
15
- const ERROR_CODES = [
16
- "nudo:constraint-violated",
17
- "nudo:assign-mismatch",
18
- "nudo:arg-structure",
19
- ] as const;
20
-
21
- describe("real package precision (commander)", () => {
22
- const hasPkg = existsSync(commanderLib);
23
-
24
- it.runIf(hasPkg)("no false-positive errors (constraint / assign / arg-structure)", () => {
25
- const files = readdirSync(commanderLib).filter((f) => f.endsWith(".js"));
26
- expect(files.length).toBeGreaterThan(0);
27
-
28
- const violations: string[] = [];
29
- let scanned = 0;
30
- for (const f of files) {
31
- const source = readFileSync(join(commanderLib, f), "utf8");
32
- const r = checkSource(`commander/${f}`, source);
33
- scanned++;
34
- for (const i of r.issues) {
35
- if (i.severity === "error" && (ERROR_CODES as readonly string[]).includes(i.code)) {
36
- violations.push(`commander/${f}:${i.line ?? "?"} [${i.code}] ${i.message}`);
37
- }
38
- }
39
- }
40
- expect(scanned).toBeGreaterThan(3);
41
- expect(violations, violations.join("\n")).toEqual([]);
42
- });
43
- });