@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,49 @@
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
+ });
@@ -0,0 +1,43 @@
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
+ });
@@ -0,0 +1,165 @@
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 { createRequire } from "node:module";
6
+ import { checkSource } from "../index.ts";
7
+
8
+ /**
9
+ * 真实包精度门禁:error 级误报必须为 0。
10
+ * 包不存在时跳过(非 monorepo / 未装依赖)。
11
+ */
12
+
13
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../..");
14
+ const require = createRequire(import.meta.url);
15
+
16
+ const ERROR_CODES = [
17
+ "nudo:constraint-violated",
18
+ "nudo:assign-mismatch",
19
+ "nudo:arg-structure",
20
+ "nudo:case-inconsistency",
21
+ ] as const;
22
+
23
+ function pkgJsFiles(pkgName: string): { label: string; source: string }[] {
24
+ let pkgRoot: string | undefined;
25
+ // 先试 package.json;exports 未暴露时从主入口反推
26
+ try {
27
+ pkgRoot = dirname(require.resolve(`${pkgName}/package.json`));
28
+ } catch {
29
+ try {
30
+ let p = require.resolve(pkgName);
31
+ // 主入口可能在 lib/ 或 src/;向上找到含 package.json 的目录
32
+ for (let i = 0; i < 4; i++) {
33
+ const parent = dirname(p);
34
+ if (existsSync(join(parent, "package.json"))) {
35
+ pkgRoot = parent;
36
+ break;
37
+ }
38
+ p = parent;
39
+ }
40
+ } catch {
41
+ return [];
42
+ }
43
+ }
44
+ if (!pkgRoot) return [];
45
+ const out: { label: string; source: string }[] = [];
46
+ const walk = (dir: string): void => {
47
+ let entries;
48
+ try {
49
+ entries = readdirSync(dir, { withFileTypes: true });
50
+ } catch {
51
+ return;
52
+ }
53
+ for (const e of entries) {
54
+ if (e.name === "node_modules" || e.name.startsWith(".") || e.name === "tests" || e.name === "typings") continue;
55
+ const p = join(dir, e.name);
56
+ if (e.isDirectory()) {
57
+ walk(p);
58
+ } else if (/\.(mjs|cjs)$/.test(e.name) || e.name.endsWith(".js")) {
59
+ try {
60
+ out.push({
61
+ label: `${pkgName}/${p.slice(pkgRoot!.length + 1)}`,
62
+ source: readFileSync(p, "utf8"),
63
+ });
64
+ } catch {
65
+ // skip
66
+ }
67
+ }
68
+ }
69
+ };
70
+ walk(pkgRoot);
71
+ return out;
72
+ }
73
+
74
+ function scanPackage(pkgName: string): { scanned: number; violations: string[] } {
75
+ const files = pkgJsFiles(pkgName);
76
+ const violations: string[] = [];
77
+ let scanned = 0;
78
+ for (const { label, source } of files) {
79
+ let r;
80
+ try {
81
+ r = checkSource(label, source);
82
+ } catch {
83
+ continue;
84
+ }
85
+ scanned++;
86
+ for (const i of r.issues) {
87
+ if (i.severity === "error" && (ERROR_CODES as readonly string[]).includes(i.code)) {
88
+ violations.push(`${label}:${i.line ?? "?"} [${i.code}] ${i.message}`);
89
+ }
90
+ }
91
+ }
92
+ return { scanned, violations };
93
+ }
94
+
95
+ describe("real package precision", () => {
96
+ it.runIf(existsSync(join(root, "node_modules/commander/lib")))(
97
+ "commander: no false-positive errors",
98
+ () => {
99
+ const { scanned, violations } = scanPackage("commander");
100
+ expect(scanned).toBeGreaterThan(3);
101
+ expect(violations, violations.join("\n")).toEqual([]);
102
+ },
103
+ );
104
+
105
+ it("escape-string-regexp: no false-positive errors", () => {
106
+ const { scanned, violations } = scanPackage("escape-string-regexp");
107
+ expect(scanned).toBeGreaterThan(0);
108
+ expect(violations, violations.join("\n")).toEqual([]);
109
+ });
110
+
111
+ it("is-plain-obj: no false-positive errors", () => {
112
+ const { scanned, violations } = scanPackage("is-plain-obj");
113
+ expect(scanned).toBeGreaterThan(0);
114
+ expect(violations, violations.join("\n")).toEqual([]);
115
+ });
116
+
117
+ it("debug: no false-positive errors", () => {
118
+ const { scanned, violations } = scanPackage("debug");
119
+ expect(scanned).toBeGreaterThan(0);
120
+ expect(violations, violations.join("\n")).toEqual([]);
121
+ });
122
+
123
+ it("yocto-queue (class): no false-positive errors", () => {
124
+ const { scanned, violations } = scanPackage("yocto-queue");
125
+ expect(scanned).toBeGreaterThan(0);
126
+ expect(violations, violations.join("\n")).toEqual([]);
127
+ });
128
+
129
+ it("p-limit: no false-positive errors", () => {
130
+ const { scanned, violations } = scanPackage("p-limit");
131
+ expect(scanned).toBeGreaterThan(0);
132
+ expect(violations, violations.join("\n")).toEqual([]);
133
+ });
134
+
135
+ it("kleur: no false-positive errors", () => {
136
+ const { scanned, violations } = scanPackage("kleur");
137
+ expect(scanned).toBeGreaterThan(0);
138
+ expect(violations, violations.join("\n")).toEqual([]);
139
+ });
140
+
141
+ it("eventemitter3: no false-positive errors", () => {
142
+ const { scanned, violations } = scanPackage("eventemitter3");
143
+ expect(scanned).toBeGreaterThan(0);
144
+ expect(violations, violations.join("\n")).toEqual([]);
145
+ });
146
+
147
+ it.runIf(existsSync(join(root, "node_modules/ms")))(
148
+ "ms: no false-positive errors",
149
+ () => {
150
+ const { scanned, violations } = scanPackage("ms");
151
+ expect(scanned).toBeGreaterThan(0);
152
+ expect(violations, violations.join("\n")).toEqual([]);
153
+ },
154
+ );
155
+
156
+ it.runIf(existsSync(join(root, "node_modules/lodash")))(
157
+ "lodash: no false-positive errors",
158
+ () => {
159
+ const { scanned, violations } = scanPackage("lodash");
160
+ // lodash 体积大:至少扫到一批入口文件
161
+ expect(scanned).toBeGreaterThan(5);
162
+ expect(violations, violations.join("\n").slice(0, 2000)).toEqual([]);
163
+ },
164
+ );
165
+ });