@euconform/core 1.0.1 → 1.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 (183) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/dist/evidence/bundle.d.ts +23 -0
  4. package/dist/evidence/bundle.d.ts.map +1 -0
  5. package/dist/evidence/bundle.js +44 -0
  6. package/dist/evidence/compliance-evaluation.d.ts +12 -0
  7. package/dist/evidence/compliance-evaluation.d.ts.map +1 -0
  8. package/dist/evidence/compliance-evaluation.js +78 -0
  9. package/dist/evidence/hash.d.ts +2 -0
  10. package/dist/evidence/hash.d.ts.map +1 -0
  11. package/dist/evidence/hash.js +4 -0
  12. package/dist/evidence/index.d.ts +13 -0
  13. package/dist/evidence/index.d.ts.map +1 -0
  14. package/dist/evidence/index.js +11 -0
  15. package/dist/evidence/markdown.d.ts +9 -0
  16. package/dist/evidence/markdown.d.ts.map +1 -0
  17. package/dist/evidence/markdown.js +169 -0
  18. package/dist/evidence/output.d.ts +13 -0
  19. package/dist/evidence/output.d.ts.map +1 -0
  20. package/dist/evidence/output.js +547 -0
  21. package/dist/evidence/types.d.ts +230 -0
  22. package/dist/evidence/types.d.ts.map +1 -0
  23. package/dist/evidence/types.js +7 -0
  24. package/dist/evidence/validate.d.ts +8 -0
  25. package/dist/evidence/validate.d.ts.map +1 -0
  26. package/dist/evidence/validate.js +175 -0
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/inference/ollama-client.d.ts +3 -0
  31. package/dist/inference/ollama-client.d.ts.map +1 -1
  32. package/dist/inference/ollama-client.js +69 -71
  33. package/dist/legal-checks/annex-iv-report.d.ts +3 -0
  34. package/dist/legal-checks/annex-iv-report.d.ts.map +1 -1
  35. package/dist/legal-checks/annex-iv-report.js +1 -0
  36. package/dist/legal-checks/deadline-timeline.d.ts +57 -0
  37. package/dist/legal-checks/deadline-timeline.d.ts.map +1 -0
  38. package/dist/legal-checks/deadline-timeline.js +265 -0
  39. package/dist/legal-checks/gap-analysis.d.ts +48 -0
  40. package/dist/legal-checks/gap-analysis.d.ts.map +1 -0
  41. package/dist/legal-checks/gap-analysis.js +397 -0
  42. package/dist/legal-checks/gpai-classifier.d.ts +49 -0
  43. package/dist/legal-checks/gpai-classifier.d.ts.map +1 -0
  44. package/dist/legal-checks/gpai-classifier.js +197 -0
  45. package/dist/legal-checks/index.d.ts +6 -0
  46. package/dist/legal-checks/index.d.ts.map +1 -1
  47. package/dist/legal-checks/index.js +3 -0
  48. package/dist/scanner/aggregator.d.ts +7 -0
  49. package/dist/scanner/aggregator.d.ts.map +1 -0
  50. package/dist/scanner/aggregator.js +200 -0
  51. package/dist/scanner/detectors/ai-framework-detector.d.ts +3 -0
  52. package/dist/scanner/detectors/ai-framework-detector.d.ts.map +1 -0
  53. package/dist/scanner/detectors/ai-framework-detector.js +74 -0
  54. package/dist/scanner/detectors/ai-provider-detector.d.ts +3 -0
  55. package/dist/scanner/detectors/ai-provider-detector.d.ts.map +1 -0
  56. package/dist/scanner/detectors/ai-provider-detector.js +100 -0
  57. package/dist/scanner/detectors/compliance-detector.d.ts +3 -0
  58. package/dist/scanner/detectors/compliance-detector.d.ts.map +1 -0
  59. package/dist/scanner/detectors/compliance-detector.js +201 -0
  60. package/dist/scanner/detectors/config-detector.d.ts +3 -0
  61. package/dist/scanner/detectors/config-detector.d.ts.map +1 -0
  62. package/dist/scanner/detectors/config-detector.js +248 -0
  63. package/dist/scanner/detectors/framework-detector.d.ts +3 -0
  64. package/dist/scanner/detectors/framework-detector.d.ts.map +1 -0
  65. package/dist/scanner/detectors/framework-detector.js +141 -0
  66. package/dist/scanner/detectors/index.d.ts +8 -0
  67. package/dist/scanner/detectors/index.d.ts.map +1 -0
  68. package/dist/scanner/detectors/index.js +37 -0
  69. package/dist/scanner/detectors/local-inference-detector.d.ts +3 -0
  70. package/dist/scanner/detectors/local-inference-detector.d.ts.map +1 -0
  71. package/dist/scanner/detectors/local-inference-detector.js +93 -0
  72. package/dist/scanner/detectors/markdown-detector.d.ts +3 -0
  73. package/dist/scanner/detectors/markdown-detector.d.ts.map +1 -0
  74. package/dist/scanner/detectors/markdown-detector.js +139 -0
  75. package/dist/scanner/detectors/package-json-detector.d.ts +3 -0
  76. package/dist/scanner/detectors/package-json-detector.d.ts.map +1 -0
  77. package/dist/scanner/detectors/package-json-detector.js +166 -0
  78. package/dist/scanner/detectors/rag-detector.d.ts +3 -0
  79. package/dist/scanner/detectors/rag-detector.d.ts.map +1 -0
  80. package/dist/scanner/detectors/rag-detector.js +132 -0
  81. package/dist/scanner/detectors/shared.d.ts +18 -0
  82. package/dist/scanner/detectors/shared.d.ts.map +1 -0
  83. package/dist/scanner/detectors/shared.js +36 -0
  84. package/dist/scanner/discovery.d.ts +14 -0
  85. package/dist/scanner/discovery.d.ts.map +1 -0
  86. package/dist/scanner/discovery.js +235 -0
  87. package/dist/scanner/index.d.ts +9 -0
  88. package/dist/scanner/index.d.ts.map +1 -0
  89. package/dist/scanner/index.js +8 -0
  90. package/package.json +6 -3
  91. package/src/evidence/bundle.ts +65 -0
  92. package/src/evidence/compliance-evaluation.ts +114 -0
  93. package/src/evidence/hash.ts +5 -0
  94. package/src/evidence/index.ts +51 -0
  95. package/src/evidence/markdown.ts +226 -0
  96. package/src/evidence/output.ts +717 -0
  97. package/src/evidence/types.ts +329 -0
  98. package/src/evidence/validate.ts +270 -0
  99. package/src/index.ts +25 -0
  100. package/src/inference/ollama-client.ts +93 -86
  101. package/src/legal-checks/annex-iv-report.ts +4 -0
  102. package/src/legal-checks/deadline-timeline.ts +313 -0
  103. package/src/legal-checks/gap-analysis.ts +454 -0
  104. package/src/legal-checks/gpai-classifier.ts +281 -0
  105. package/src/legal-checks/index.ts +33 -0
  106. package/src/scanner/aggregator.ts +258 -0
  107. package/src/scanner/detectors/ai-framework-detector.ts +94 -0
  108. package/src/scanner/detectors/ai-provider-detector.ts +135 -0
  109. package/src/scanner/detectors/compliance-detector.ts +232 -0
  110. package/src/scanner/detectors/config-detector.ts +316 -0
  111. package/src/scanner/detectors/framework-detector.ts +163 -0
  112. package/src/scanner/detectors/index.ts +40 -0
  113. package/src/scanner/detectors/local-inference-detector.ts +124 -0
  114. package/src/scanner/detectors/markdown-detector.ts +176 -0
  115. package/src/scanner/detectors/package-json-detector.ts +202 -0
  116. package/src/scanner/detectors/rag-detector.ts +162 -0
  117. package/src/scanner/detectors/shared.ts +45 -0
  118. package/src/scanner/discovery.ts +290 -0
  119. package/src/scanner/index.ts +9 -0
  120. package/tests/evidence/bundle.test.ts +128 -0
  121. package/tests/evidence/ecef-schemas.test.ts +316 -0
  122. package/tests/evidence/hash.test.ts +25 -0
  123. package/tests/evidence/markdown.test.ts +92 -0
  124. package/tests/evidence/output.test.ts +203 -0
  125. package/tests/fixtures/compliance-good/README.md +14 -0
  126. package/tests/fixtures/compliance-good/lib/ai-service.ts +17 -0
  127. package/tests/fixtures/compliance-good/lib/review-flow.ts +11 -0
  128. package/tests/fixtures/compliance-good/package.json +10 -0
  129. package/tests/fixtures/compliance-good/tests/bias-check.test.ts +13 -0
  130. package/tests/fixtures/nextjs-openai/README.md +5 -0
  131. package/tests/fixtures/nextjs-openai/app/page.tsx +11 -0
  132. package/tests/fixtures/nextjs-openai/package.json +9 -0
  133. package/tests/fixtures/ollama-rag/.env.example +2 -0
  134. package/tests/fixtures/ollama-rag/docker-compose.yml +9 -0
  135. package/tests/fixtures/ollama-rag/package.json +9 -0
  136. package/tests/fixtures/ollama-rag/server.ts +21 -0
  137. package/tests/fixtures/plain-webapp/README.md +3 -0
  138. package/tests/fixtures/plain-webapp/index.js +5 -0
  139. package/tests/fixtures/plain-webapp/package.json +8 -0
  140. package/tests/gpai-classifier.test.ts +125 -0
  141. package/tests/gpai-timeline.test.ts +55 -0
  142. package/tests/scanner/aggregator.test.ts +122 -0
  143. package/tests/scanner/detectors.test.ts +274 -0
  144. package/tests/scanner/discovery.test.ts +87 -0
  145. package/vitest.config.ts +1 -0
  146. package/.turbo/turbo-check-types.log +0 -4
  147. package/.turbo/turbo-test.log +0 -364
  148. package/coverage/base.css +0 -224
  149. package/coverage/block-navigation.js +0 -87
  150. package/coverage/clover.xml +0 -3282
  151. package/coverage/coverage-final.json +0 -20
  152. package/coverage/favicon.png +0 -0
  153. package/coverage/index.html +0 -161
  154. package/coverage/prettify.css +0 -1
  155. package/coverage/prettify.js +0 -2
  156. package/coverage/sort-arrow-sprite.png +0 -0
  157. package/coverage/sorter.js +0 -210
  158. package/coverage/src/fairness-metrics.ts.html +0 -1579
  159. package/coverage/src/index.html +0 -161
  160. package/coverage/src/index.ts.html +0 -535
  161. package/coverage/src/inference/browser-inference.ts.html +0 -859
  162. package/coverage/src/inference/capability-detection.ts.html +0 -2227
  163. package/coverage/src/inference/index.html +0 -176
  164. package/coverage/src/inference/index.ts.html +0 -553
  165. package/coverage/src/inference/inference-factory.ts.html +0 -751
  166. package/coverage/src/inference/ollama-client.ts.html +0 -1627
  167. package/coverage/src/legal-checks/annex-iv-report.ts.html +0 -556
  168. package/coverage/src/legal-checks/bias-metrics.ts.html +0 -1855
  169. package/coverage/src/legal-checks/data-governance.ts.html +0 -529
  170. package/coverage/src/legal-checks/human-oversight-logging.ts.html +0 -490
  171. package/coverage/src/legal-checks/index.html +0 -206
  172. package/coverage/src/legal-checks/index.ts.html +0 -250
  173. package/coverage/src/legal-checks/risk-classifier.ts.html +0 -940
  174. package/coverage/src/legal-checks/robustness-transparency.ts.html +0 -571
  175. package/coverage/src/metrics/crows-pairs-bias.ts.html +0 -820
  176. package/coverage/src/metrics/index.html +0 -146
  177. package/coverage/src/metrics/index.ts.html +0 -151
  178. package/coverage/src/metrics/stereotype-bias.ts.html +0 -886
  179. package/coverage/src/risk-engine.ts.html +0 -1660
  180. package/coverage/src/types.ts.html +0 -547
  181. package/dist/legal-checks/disclaimer.d.ts +0 -2
  182. package/dist/legal-checks/disclaimer.d.ts.map +0 -1
  183. package/dist/legal-checks/disclaimer.js +0 -1
@@ -0,0 +1,274 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { DetectorContext, ScanFile } from "../../src/evidence/types";
3
+ import { detectAiFrameworkSignals } from "../../src/scanner/detectors/ai-framework-detector";
4
+ import { detectAiProviderSignals } from "../../src/scanner/detectors/ai-provider-detector";
5
+ import { detectCompliance } from "../../src/scanner/detectors/compliance-detector";
6
+ import { detectConfig } from "../../src/scanner/detectors/config-detector";
7
+ import { detectFrameworks } from "../../src/scanner/detectors/framework-detector";
8
+ import { detectLocalInferenceSignals } from "../../src/scanner/detectors/local-inference-detector";
9
+ import { detectMarkdown } from "../../src/scanner/detectors/markdown-detector";
10
+ import { detectPackageJsonSignals } from "../../src/scanner/detectors/package-json-detector";
11
+ import { detectRagSignals } from "../../src/scanner/detectors/rag-detector";
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Helper
15
+ // ---------------------------------------------------------------------------
16
+
17
+ function makeContext(
18
+ file: Partial<ScanFile> & { content: string; relativePath: string }
19
+ ): DetectorContext {
20
+ const extension =
21
+ file.extension ??
22
+ (file.relativePath.split(".").pop() ? `.${file.relativePath.split(".").pop()}` : "");
23
+ const provenance =
24
+ file.provenance ??
25
+ (extension === ".md" && !file.relativePath.includes("/") ? "root-docs" : "runtime");
26
+
27
+ const scanFile = {
28
+ relativePath: file.relativePath,
29
+ absolutePath: `/test/${file.relativePath}`,
30
+ extension,
31
+ content: file.content,
32
+ sizeBytes: file.content.length,
33
+ provenance,
34
+ };
35
+
36
+ return {
37
+ file: scanFile,
38
+ lines: scanFile.content.split("\n"),
39
+ allFiles: [],
40
+ };
41
+ }
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // package-json-detector
45
+ // ---------------------------------------------------------------------------
46
+
47
+ describe("package-json-detector", () => {
48
+ it("detects AI provider and framework signals from package.json", () => {
49
+ const ctx = makeContext({
50
+ relativePath: "package.json",
51
+ extension: ".json",
52
+ content: JSON.stringify({
53
+ dependencies: {
54
+ openai: "^4.0.0",
55
+ next: "^14.0.0",
56
+ },
57
+ }),
58
+ });
59
+
60
+ const signals = detectPackageJsonSignals(ctx);
61
+
62
+ const categories = signals.map((s) => s.category);
63
+ expect(categories).toContain("ai-provider");
64
+ expect(categories).toContain("framework");
65
+
66
+ const openaiSignal = signals.find((s) => s.category === "ai-provider");
67
+ expect(openaiSignal).toBeDefined();
68
+ expect(openaiSignal?.confidence).toBe("high");
69
+ });
70
+
71
+ it("returns empty for non-package files", () => {
72
+ const ctx = makeContext({
73
+ relativePath: "src/index.ts",
74
+ extension: ".ts",
75
+ content: '{ "openai": "^4.0.0" }',
76
+ });
77
+
78
+ expect(detectPackageJsonSignals(ctx)).toHaveLength(0);
79
+ });
80
+ });
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // ai-provider-detector
84
+ // ---------------------------------------------------------------------------
85
+
86
+ describe("ai-provider-detector", () => {
87
+ it("detects OpenAI import in TypeScript", () => {
88
+ const ctx = makeContext({
89
+ relativePath: "src/ai.ts",
90
+ extension: ".ts",
91
+ content: 'import OpenAI from "openai";\n\nconst client = new OpenAI();',
92
+ });
93
+
94
+ const signals = detectAiProviderSignals(ctx);
95
+
96
+ expect(signals.length).toBeGreaterThanOrEqual(1);
97
+ expect(signals[0]?.category).toBe("ai-provider");
98
+ expect(signals[0]?.id).toBe("ai-provider-openai");
99
+ });
100
+
101
+ it("ignores non-source files", () => {
102
+ const ctx = makeContext({
103
+ relativePath: "README.md",
104
+ extension: ".md",
105
+ content: 'import OpenAI from "openai";',
106
+ });
107
+
108
+ expect(detectAiProviderSignals(ctx)).toHaveLength(0);
109
+ });
110
+ });
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // ai-framework-detector
114
+ // ---------------------------------------------------------------------------
115
+
116
+ describe("ai-framework-detector", () => {
117
+ it("detects LangChain import", () => {
118
+ const ctx = makeContext({
119
+ relativePath: "src/chain.ts",
120
+ extension: ".ts",
121
+ content: 'import { ChatOpenAI } from "langchain/chat_models";\n',
122
+ });
123
+
124
+ const signals = detectAiFrameworkSignals(ctx);
125
+
126
+ expect(signals.length).toBeGreaterThanOrEqual(1);
127
+ expect(signals[0]?.category).toBe("ai-framework");
128
+ expect(signals[0]?.id).toContain("langchain");
129
+ });
130
+ });
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // local-inference-detector
134
+ // ---------------------------------------------------------------------------
135
+
136
+ describe("local-inference-detector", () => {
137
+ it("detects Ollama localhost URL", () => {
138
+ const ctx = makeContext({
139
+ relativePath: "src/llm.ts",
140
+ extension: ".ts",
141
+ content: 'new Ollama({ host: "http://localhost:11434" })',
142
+ });
143
+
144
+ const signals = detectLocalInferenceSignals(ctx);
145
+
146
+ expect(signals.length).toBeGreaterThanOrEqual(1);
147
+ expect(signals.some((s) => s.category === "local-inference")).toBe(true);
148
+ // localhost:11434 is a high-confidence signal
149
+ const ollamaSignal = signals.find((s) => s.id.includes("ollama-api"));
150
+ expect(ollamaSignal).toBeDefined();
151
+ expect(ollamaSignal?.confidence).toBe("high");
152
+ });
153
+ });
154
+
155
+ // ---------------------------------------------------------------------------
156
+ // rag-detector
157
+ // ---------------------------------------------------------------------------
158
+
159
+ describe("rag-detector", () => {
160
+ it("detects ChromaDB import", () => {
161
+ const ctx = makeContext({
162
+ relativePath: "src/rag.ts",
163
+ extension: ".ts",
164
+ content: 'import { ChromaClient } from "chromadb";\n\nconst chroma = new ChromaClient();',
165
+ });
166
+
167
+ const signals = detectRagSignals(ctx);
168
+
169
+ expect(signals.length).toBeGreaterThanOrEqual(1);
170
+ expect(signals.some((s) => s.category === "rag")).toBe(true);
171
+ const chromaSignal = signals.find((s) => s.id === "rag-chromadb");
172
+ expect(chromaSignal).toBeDefined();
173
+ expect(chromaSignal?.confidence).toBe("high");
174
+ });
175
+ });
176
+
177
+ // ---------------------------------------------------------------------------
178
+ // framework-detector
179
+ // ---------------------------------------------------------------------------
180
+
181
+ describe("framework-detector", () => {
182
+ it("detects Next.js from config file", () => {
183
+ const ctx = makeContext({
184
+ relativePath: "next.config.ts",
185
+ extension: ".ts",
186
+ content: "export default { reactStrictMode: true };",
187
+ });
188
+
189
+ const signals = detectFrameworks(ctx);
190
+
191
+ expect(signals.length).toBeGreaterThanOrEqual(1);
192
+ const nextSignal = signals.find((s) => s.id === "framework-nextjs");
193
+ expect(nextSignal).toBeDefined();
194
+ expect(nextSignal?.category).toBe("framework");
195
+ expect(nextSignal?.confidence).toBe("high");
196
+ });
197
+ });
198
+
199
+ // ---------------------------------------------------------------------------
200
+ // compliance-detector
201
+ // ---------------------------------------------------------------------------
202
+
203
+ describe("compliance-detector", () => {
204
+ it("detects AI disclosure text and logging library", () => {
205
+ const ctx = makeContext({
206
+ relativePath: "app/page.tsx",
207
+ extension: ".tsx",
208
+ content: [
209
+ 'import pino from "pino";',
210
+ "const logger = pino();",
211
+ '// This response was "generated by AI"',
212
+ 'logger.info({ action: "ai-response" }, "done");',
213
+ ].join("\n"),
214
+ });
215
+
216
+ const signals = detectCompliance(ctx);
217
+
218
+ const categories = signals.map((s) => s.category);
219
+ expect(categories).toContain("compliance-disclosure");
220
+ expect(categories).toContain("compliance-logging");
221
+ });
222
+ });
223
+
224
+ // ---------------------------------------------------------------------------
225
+ // config-detector
226
+ // ---------------------------------------------------------------------------
227
+
228
+ describe("config-detector", () => {
229
+ it("detects AI provider from .env.example", () => {
230
+ const ctx = makeContext({
231
+ relativePath: ".env.example",
232
+ extension: "",
233
+ content: "OPENAI_API_KEY=\nDATABASE_URL=postgres://localhost/db\n",
234
+ });
235
+
236
+ const signals = detectConfig(ctx);
237
+
238
+ expect(signals.length).toBeGreaterThanOrEqual(1);
239
+ const openaiSignal = signals.find((s) => s.category === "ai-provider");
240
+ expect(openaiSignal).toBeDefined();
241
+ expect(openaiSignal?.confidence).toBe("high");
242
+ // Ensure the value is not leaked — only the key name
243
+ expect(openaiSignal?.evidence[0]?.snippet).not.toContain("=");
244
+ });
245
+ });
246
+
247
+ // ---------------------------------------------------------------------------
248
+ // markdown-detector
249
+ // ---------------------------------------------------------------------------
250
+
251
+ describe("markdown-detector", () => {
252
+ it("detects AI disclosure in README", () => {
253
+ const ctx = makeContext({
254
+ relativePath: "README.md",
255
+ extension: ".md",
256
+ content: "# My App\n\nThis app uses artificial intelligence to generate responses.\n",
257
+ });
258
+
259
+ const signals = detectMarkdown(ctx);
260
+
261
+ expect(signals.length).toBeGreaterThanOrEqual(1);
262
+ expect(signals.some((s) => s.category === "compliance-disclosure")).toBe(true);
263
+ });
264
+
265
+ it("ignores non-markdown files", () => {
266
+ const ctx = makeContext({
267
+ relativePath: "src/index.ts",
268
+ extension: ".ts",
269
+ content: "This app uses artificial intelligence",
270
+ });
271
+
272
+ expect(detectMarkdown(ctx)).toHaveLength(0);
273
+ });
274
+ });
@@ -0,0 +1,87 @@
1
+ import { resolve } from "node:path";
2
+ import { describe, expect, it } from "vitest";
3
+ import { discoverFiles } from "../../src/scanner/discovery";
4
+
5
+ const FIXTURES = resolve(__dirname, "../fixtures");
6
+
7
+ describe("discoverFiles", () => {
8
+ it("discovers files in a fixture directory", async () => {
9
+ const { files } = await discoverFiles({
10
+ targetPath: resolve(FIXTURES, "nextjs-openai"),
11
+ });
12
+
13
+ const paths = files.map((f) => f.relativePath);
14
+ expect(paths).toContain("package.json");
15
+ expect(paths.some((p) => p.includes("app/page.tsx"))).toBe(true);
16
+ expect(paths).toContain("README.md");
17
+ });
18
+
19
+ it("respects extension filtering", async () => {
20
+ const { files } = await discoverFiles({
21
+ targetPath: resolve(FIXTURES, "nextjs-openai"),
22
+ });
23
+
24
+ // All discovered files should match default extensions or named file patterns
25
+ for (const file of files) {
26
+ const ext = file.extension;
27
+ const isDefaultExt = [".ts", ".tsx", ".js", ".jsx", ".json", ".md", ".yaml", ".yml"].includes(
28
+ ext
29
+ );
30
+ const isNamedFile =
31
+ /^(package\.json|\.env\.|next\.config\.|vite\.config\.|docker-compose|Dockerfile|tsconfig)/.test(
32
+ file.relativePath.split("/").pop() ?? ""
33
+ );
34
+ expect(isDefaultExt || isNamedFile).toBe(true);
35
+ }
36
+ });
37
+
38
+ it("skips node_modules", async () => {
39
+ const { files } = await discoverFiles({
40
+ targetPath: resolve(FIXTURES, "nextjs-openai"),
41
+ });
42
+
43
+ const hasNodeModules = files.some((f) => f.relativePath.includes("node_modules"));
44
+ expect(hasNodeModules).toBe(false);
45
+ });
46
+
47
+ it("defaults to production scope and excludes test/example files", async () => {
48
+ const { files } = await discoverFiles({
49
+ targetPath: resolve(FIXTURES, "compliance-good"),
50
+ });
51
+
52
+ const paths = files.map((file) => file.relativePath);
53
+ expect(paths.some((path) => path.includes("tests/"))).toBe(false);
54
+ });
55
+
56
+ it("includes test files in all scope and annotates provenance", async () => {
57
+ const { files } = await discoverFiles({
58
+ targetPath: resolve(FIXTURES, "compliance-good"),
59
+ scope: "all",
60
+ });
61
+
62
+ const testFile = files.find((file) => file.relativePath.includes("tests/bias-check.test.ts"));
63
+ expect(testFile).toBeDefined();
64
+ expect(testFile?.provenance).toBe("test");
65
+ });
66
+
67
+ it("respects max file size", async () => {
68
+ // Set a very small max file size — only tiny files should be included
69
+ const { files } = await discoverFiles({
70
+ targetPath: resolve(FIXTURES, "nextjs-openai"),
71
+ maxFileSizeBytes: 10,
72
+ });
73
+
74
+ // All included files should be at most 10 bytes
75
+ for (const file of files) {
76
+ expect(file.sizeBytes).toBeLessThanOrEqual(10);
77
+ }
78
+ });
79
+
80
+ it("handles non-existent path", async () => {
81
+ await expect(
82
+ discoverFiles({
83
+ targetPath: resolve(FIXTURES, "this-does-not-exist"),
84
+ })
85
+ ).rejects.toThrow(/Cannot read directory/);
86
+ });
87
+ });
package/vitest.config.ts CHANGED
@@ -5,6 +5,7 @@ export default defineConfig({
5
5
  globals: true,
6
6
  environment: "node",
7
7
  include: ["tests/**/*.test.ts"],
8
+ exclude: ["tests/fixtures/**"],
8
9
  // Work around rare worker-pool teardown issues (tinypool) on some Node/tooling combos.
9
10
  // Core tests are lightweight; single-thread execution improves stability and reproducibility.
10
11
  pool: "threads",
@@ -1,4 +0,0 @@
1
-
2
- > @repo/core@0.0.0 check-types /Users/benedikthiepler/projects/priv/aimpact/packages/core
3
- > tsc --noEmit
4
-