@rigour-labs/core 3.0.5 → 4.0.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 (85) hide show
  1. package/dist/deep/fact-extractor.d.ts +80 -0
  2. package/dist/deep/fact-extractor.js +626 -0
  3. package/dist/deep/index.d.ts +14 -0
  4. package/dist/deep/index.js +12 -0
  5. package/dist/deep/prompts.d.ts +22 -0
  6. package/dist/deep/prompts.js +374 -0
  7. package/dist/deep/verifier.d.ts +16 -0
  8. package/dist/deep/verifier.js +388 -0
  9. package/dist/gates/deep-analysis.d.ts +28 -0
  10. package/dist/gates/deep-analysis.js +302 -0
  11. package/dist/gates/deprecated-apis-rules-lang.d.ts +21 -0
  12. package/dist/gates/deprecated-apis-rules-lang.js +311 -0
  13. package/dist/gates/deprecated-apis-rules-node.d.ts +19 -0
  14. package/dist/gates/deprecated-apis-rules-node.js +199 -0
  15. package/dist/gates/deprecated-apis-rules.d.ts +6 -0
  16. package/dist/gates/deprecated-apis-rules.js +6 -0
  17. package/dist/gates/deprecated-apis.js +1 -502
  18. package/dist/gates/hallucinated-imports-lang.d.ts +16 -0
  19. package/dist/gates/hallucinated-imports-lang.js +374 -0
  20. package/dist/gates/hallucinated-imports-stdlib.d.ts +12 -0
  21. package/dist/gates/hallucinated-imports-stdlib.js +228 -0
  22. package/dist/gates/hallucinated-imports.d.ts +0 -98
  23. package/dist/gates/hallucinated-imports.js +10 -678
  24. package/dist/gates/phantom-apis-data.d.ts +33 -0
  25. package/dist/gates/phantom-apis-data.js +398 -0
  26. package/dist/gates/phantom-apis.js +1 -393
  27. package/dist/gates/phantom-apis.test.js +52 -0
  28. package/dist/gates/promise-safety-helpers.d.ts +19 -0
  29. package/dist/gates/promise-safety-helpers.js +101 -0
  30. package/dist/gates/promise-safety-rules.d.ts +7 -0
  31. package/dist/gates/promise-safety-rules.js +19 -0
  32. package/dist/gates/promise-safety.d.ts +1 -21
  33. package/dist/gates/promise-safety.js +51 -257
  34. package/dist/gates/runner.d.ts +4 -2
  35. package/dist/gates/runner.js +46 -1
  36. package/dist/gates/test-quality-lang.d.ts +30 -0
  37. package/dist/gates/test-quality-lang.js +188 -0
  38. package/dist/gates/test-quality.d.ts +0 -14
  39. package/dist/gates/test-quality.js +13 -186
  40. package/dist/index.d.ts +10 -0
  41. package/dist/index.js +12 -2
  42. package/dist/inference/cloud-provider.d.ts +34 -0
  43. package/dist/inference/cloud-provider.js +126 -0
  44. package/dist/inference/index.d.ts +17 -0
  45. package/dist/inference/index.js +23 -0
  46. package/dist/inference/model-manager.d.ts +26 -0
  47. package/dist/inference/model-manager.js +106 -0
  48. package/dist/inference/sidecar-provider.d.ts +15 -0
  49. package/dist/inference/sidecar-provider.js +153 -0
  50. package/dist/inference/types.d.ts +77 -0
  51. package/dist/inference/types.js +19 -0
  52. package/dist/pattern-index/indexer-helpers.d.ts +38 -0
  53. package/dist/pattern-index/indexer-helpers.js +111 -0
  54. package/dist/pattern-index/indexer-lang.d.ts +13 -0
  55. package/dist/pattern-index/indexer-lang.js +244 -0
  56. package/dist/pattern-index/indexer-ts.d.ts +22 -0
  57. package/dist/pattern-index/indexer-ts.js +258 -0
  58. package/dist/pattern-index/indexer.d.ts +4 -106
  59. package/dist/pattern-index/indexer.js +58 -707
  60. package/dist/pattern-index/staleness-data.d.ts +6 -0
  61. package/dist/pattern-index/staleness-data.js +262 -0
  62. package/dist/pattern-index/staleness.js +1 -258
  63. package/dist/settings.d.ts +104 -0
  64. package/dist/settings.js +186 -0
  65. package/dist/storage/db.d.ts +16 -0
  66. package/dist/storage/db.js +132 -0
  67. package/dist/storage/findings.d.ts +14 -0
  68. package/dist/storage/findings.js +38 -0
  69. package/dist/storage/index.d.ts +9 -0
  70. package/dist/storage/index.js +8 -0
  71. package/dist/storage/patterns.d.ts +35 -0
  72. package/dist/storage/patterns.js +62 -0
  73. package/dist/storage/scans.d.ts +42 -0
  74. package/dist/storage/scans.js +55 -0
  75. package/dist/templates/index.d.ts +12 -16
  76. package/dist/templates/index.js +11 -527
  77. package/dist/templates/paradigms.d.ts +2 -0
  78. package/dist/templates/paradigms.js +46 -0
  79. package/dist/templates/presets.d.ts +14 -0
  80. package/dist/templates/presets.js +227 -0
  81. package/dist/templates/universal-config.d.ts +2 -0
  82. package/dist/templates/universal-config.js +190 -0
  83. package/dist/types/index.d.ts +438 -15
  84. package/dist/types/index.js +41 -1
  85. package/package.json +6 -2
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Language-specific import checkers and dependency loaders for hallucinated-imports gate.
3
+ * Go, Ruby, C#, Rust, Java/Kotlin parsers extracted to keep main gate file under 500 lines.
4
+ */
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+ import { isGoStdlib, isRubyStdlib, isDotNetFramework, isRustStdCrate, isJavaStdlib, isKotlinStdlib } from './hallucinated-imports-stdlib.js';
8
+ export function checkGoImports(content, file, cwd, projectFiles, hallucinated) {
9
+ const lines = content.split('\n');
10
+ let inImportBlock = false;
11
+ // Try to read go.mod for the module path
12
+ const goModPath = path.join(cwd, 'go.mod');
13
+ let modulePath = null;
14
+ try {
15
+ if (fs.pathExistsSync(goModPath)) {
16
+ const goMod = fs.readFileSync(goModPath, 'utf-8');
17
+ const moduleMatch = goMod.match(/^module\s+(\S+)/m);
18
+ if (moduleMatch)
19
+ modulePath = moduleMatch[1];
20
+ }
21
+ }
22
+ catch { /* no go.mod — skip project-relative checks entirely */ }
23
+ for (let i = 0; i < lines.length; i++) {
24
+ const line = lines[i].trim();
25
+ // Detect import block: import ( ... )
26
+ if (/^import\s*\(/.test(line)) {
27
+ inImportBlock = true;
28
+ continue;
29
+ }
30
+ if (inImportBlock && line === ')') {
31
+ inImportBlock = false;
32
+ continue;
33
+ }
34
+ // Single import: import "path" or import alias "path"
35
+ const singleMatch = line.match(/^import\s+(?:\w+\s+)?"([^"]+)"/);
36
+ const blockMatch = inImportBlock ? line.match(/^\s*(?:\w+\s+)?"([^"]+)"/) : null;
37
+ const importPath = singleMatch?.[1] || blockMatch?.[1];
38
+ if (!importPath)
39
+ continue;
40
+ // 1. Skip Go standard library — comprehensive list
41
+ if (isGoStdlib(importPath))
42
+ continue;
43
+ // 2. If we have a module path, check project-relative imports FIRST
44
+ // (project imports like github.com/myorg/project/pkg also have dots)
45
+ if (modulePath && importPath.startsWith(modulePath + '/')) {
46
+ const relPath = importPath.slice(modulePath.length + 1);
47
+ const hasMatchingFile = [...projectFiles].some(f => f.endsWith('.go') && f.startsWith(relPath));
48
+ if (!hasMatchingFile) {
49
+ hallucinated.push({
50
+ file, line: i + 1, importPath, type: 'go',
51
+ reason: `Go import '${importPath}' — package directory '${relPath}' not found in project`,
52
+ });
53
+ }
54
+ continue;
55
+ }
56
+ // 3. Skip external modules — any import containing a dot is a domain
57
+ // e.g. github.com/*, google.golang.org/*, go.uber.org/*
58
+ if (importPath.includes('.'))
59
+ continue;
60
+ // 4. No dots, no go.mod match, not stdlib → likely an internal package
61
+ // without go.mod context we can't verify, so skip to avoid false positives
62
+ }
63
+ }
64
+ export function checkRubyImports(content, file, cwd, projectFiles, hallucinated) {
65
+ const lines = content.split('\n');
66
+ // Parse Gemfile for known gem dependencies
67
+ const gemDeps = loadRubyGems(cwd);
68
+ for (let i = 0; i < lines.length; i++) {
69
+ const line = lines[i].trim();
70
+ // Skip comments
71
+ if (line.startsWith('#'))
72
+ continue;
73
+ // require_relative 'path' — must resolve to a real file
74
+ const relMatch = line.match(/require_relative\s+['"]([^'"]+)['"]/);
75
+ if (relMatch) {
76
+ const reqPath = relMatch[1];
77
+ const dir = path.dirname(file);
78
+ const resolved = path.join(dir, reqPath).replace(/\\/g, '/');
79
+ const candidates = [resolved + '.rb', resolved];
80
+ if (!candidates.some(c => projectFiles.has(c))) {
81
+ hallucinated.push({
82
+ file, line: i + 1, importPath: reqPath, type: 'ruby',
83
+ reason: `require_relative '${reqPath}' — file not found in project`,
84
+ });
85
+ }
86
+ continue;
87
+ }
88
+ // require 'something' — check stdlib, gems, then local
89
+ const reqMatch = line.match(/^require\s+['"]([^'"]+)['"]/);
90
+ if (reqMatch) {
91
+ const reqPath = reqMatch[1];
92
+ // Skip Ruby stdlib
93
+ if (isRubyStdlib(reqPath))
94
+ continue;
95
+ // Skip gems listed in Gemfile
96
+ const gemName = reqPath.split('/')[0];
97
+ if (gemDeps.has(gemName))
98
+ continue;
99
+ // Check if it resolves to a project file
100
+ const candidates = [
101
+ reqPath + '.rb',
102
+ reqPath,
103
+ 'lib/' + reqPath + '.rb',
104
+ 'lib/' + reqPath,
105
+ ];
106
+ const found = candidates.some(c => projectFiles.has(c));
107
+ if (!found) {
108
+ // If we have a Gemfile and it's not in it, it might be hallucinated
109
+ if (gemDeps.size > 0) {
110
+ hallucinated.push({
111
+ file, line: i + 1, importPath: reqPath, type: 'ruby',
112
+ reason: `require '${reqPath}' — not in stdlib, Gemfile, or project files`,
113
+ });
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ export function loadRubyGems(cwd) {
120
+ const gems = new Set();
121
+ try {
122
+ const gemfilePath = path.join(cwd, 'Gemfile');
123
+ if (fs.pathExistsSync(gemfilePath)) {
124
+ const content = fs.readFileSync(gemfilePath, 'utf-8');
125
+ const gemPattern = /gem\s+['"]([^'"]+)['"]/g;
126
+ let m;
127
+ while ((m = gemPattern.exec(content)) !== null) {
128
+ gems.add(m[1]);
129
+ }
130
+ }
131
+ // Also check .gemspec
132
+ const gemspecs = [...new Set()]; // placeholder
133
+ const files = fs.readdirSync?.(cwd) || [];
134
+ for (const f of files) {
135
+ if (typeof f === 'string' && f.endsWith('.gemspec')) {
136
+ try {
137
+ const spec = fs.readFileSync(path.join(cwd, f), 'utf-8');
138
+ const depPattern = /add_(?:runtime_)?dependency\s+['"]([^'"]+)['"]/g;
139
+ let dm;
140
+ while ((dm = depPattern.exec(spec)) !== null) {
141
+ gems.add(dm[1]);
142
+ }
143
+ }
144
+ catch { /* skip */ }
145
+ }
146
+ }
147
+ }
148
+ catch { /* no Gemfile */ }
149
+ return gems;
150
+ }
151
+ export function checkCSharpImports(content, file, cwd, projectFiles, hallucinated) {
152
+ const lines = content.split('\n');
153
+ const nugetPackages = loadNuGetPackages(cwd);
154
+ for (let i = 0; i < lines.length; i++) {
155
+ const line = lines[i].trim();
156
+ // Match: using Namespace; and using static Namespace.Class;
157
+ // Skip: using alias = Namespace; and using (var x = ...) disposable
158
+ const usingMatch = line.match(/^using\s+(?:static\s+)?([\w.]+)\s*;/);
159
+ if (!usingMatch)
160
+ continue;
161
+ const namespace = usingMatch[1];
162
+ // 1. Skip .NET framework and BCL namespaces
163
+ if (isDotNetFramework(namespace))
164
+ continue;
165
+ // 2. Skip NuGet packages from .csproj
166
+ const topLevel = namespace.split('.')[0];
167
+ if (nugetPackages.has(topLevel) || nugetPackages.has(namespace.split('.').slice(0, 2).join('.')))
168
+ continue;
169
+ // 3. Check if the namespace maps to any .cs file in the project
170
+ // C# namespaces often have a root prefix (project name) not in the directory tree
171
+ // e.g. MyProject.Services.UserService → check Services/UserService AND MyProject/Services/UserService
172
+ const nsParts = namespace.split('.');
173
+ const nsPath = namespace.replace(/\./g, '/');
174
+ // Also check without root prefix (common convention: namespace root != directory root)
175
+ const nsPathNoRoot = nsParts.slice(1).join('/');
176
+ const csFiles = [...projectFiles].filter(f => f.endsWith('.cs'));
177
+ const hasMatch = csFiles.some(f => f.includes(nsPath) || (nsPathNoRoot && f.includes(nsPathNoRoot)));
178
+ // Only flag if we have .csproj context (proves this is a real .NET project)
179
+ if (!hasMatch && namespace.includes('.') && nugetPackages.size >= 0) {
180
+ // Check if we actually have .csproj context (a real .NET project)
181
+ const hasCsproj = hasCsprojFile(cwd);
182
+ if (hasCsproj) {
183
+ hallucinated.push({
184
+ file, line: i + 1, importPath: namespace, type: 'csharp',
185
+ reason: `Namespace '${namespace}' — no matching files in project, not in NuGet packages`,
186
+ });
187
+ }
188
+ }
189
+ }
190
+ }
191
+ export function hasCsprojFile(cwd) {
192
+ try {
193
+ const files = fs.readdirSync?.(cwd) || [];
194
+ return files.some((f) => typeof f === 'string' && f.endsWith('.csproj'));
195
+ }
196
+ catch {
197
+ return false;
198
+ }
199
+ }
200
+ export function loadNuGetPackages(cwd) {
201
+ const packages = new Set();
202
+ try {
203
+ const files = fs.readdirSync?.(cwd) || [];
204
+ for (const f of files) {
205
+ if (typeof f === 'string' && f.endsWith('.csproj')) {
206
+ try {
207
+ const content = fs.readFileSync(path.join(cwd, f), 'utf-8');
208
+ const pkgPattern = /PackageReference\s+Include="([^"]+)"/g;
209
+ let m;
210
+ while ((m = pkgPattern.exec(content)) !== null) {
211
+ packages.add(m[1]);
212
+ // Also add top-level namespace (e.g. Newtonsoft.Json → Newtonsoft)
213
+ packages.add(m[1].split('.')[0]);
214
+ }
215
+ }
216
+ catch { /* skip */ }
217
+ }
218
+ }
219
+ }
220
+ catch { /* no .csproj */ }
221
+ return packages;
222
+ }
223
+ export function checkRustImports(content, file, cwd, projectFiles, hallucinated) {
224
+ const lines = content.split('\n');
225
+ const cargoDeps = loadCargoDeps(cwd);
226
+ for (let i = 0; i < lines.length; i++) {
227
+ const line = lines[i].trim();
228
+ if (line.startsWith('//') || line.startsWith('/*'))
229
+ continue;
230
+ // extern crate foo;
231
+ const externMatch = line.match(/^extern\s+crate\s+(\w+)/);
232
+ if (externMatch) {
233
+ const crateName = externMatch[1];
234
+ if (isRustStdCrate(crateName))
235
+ continue;
236
+ if (cargoDeps.has(crateName))
237
+ continue;
238
+ hallucinated.push({
239
+ file, line: i + 1, importPath: crateName, type: 'rust',
240
+ reason: `extern crate '${crateName}' — not in Cargo.toml or Rust std`,
241
+ });
242
+ continue;
243
+ }
244
+ // use foo::bar::baz; or use foo::{bar, baz};
245
+ const useMatch = line.match(/^(?:pub\s+)?use\s+(\w+)::/);
246
+ if (useMatch) {
247
+ const crateName = useMatch[1];
248
+ if (isRustStdCrate(crateName))
249
+ continue;
250
+ if (cargoDeps.has(crateName))
251
+ continue;
252
+ // 'crate' and 'self' and 'super' are Rust path keywords
253
+ if (['crate', 'self', 'super'].includes(crateName))
254
+ continue;
255
+ hallucinated.push({
256
+ file, line: i + 1, importPath: crateName, type: 'rust',
257
+ reason: `use ${crateName}:: — crate not in Cargo.toml or Rust std`,
258
+ });
259
+ }
260
+ }
261
+ }
262
+ export function loadCargoDeps(cwd) {
263
+ const deps = new Set();
264
+ try {
265
+ const cargoPath = path.join(cwd, 'Cargo.toml');
266
+ if (fs.pathExistsSync(cargoPath)) {
267
+ const content = fs.readFileSync(cargoPath, 'utf-8');
268
+ // Match [dependencies] section entries: name = "version" or name = { ... }
269
+ const depPattern = /^\s*(\w[\w-]*)\s*=/gm;
270
+ let inDeps = false;
271
+ for (const line of content.split('\n')) {
272
+ if (/^\[(?:.*-)?dependencies/.test(line.trim())) {
273
+ inDeps = true;
274
+ continue;
275
+ }
276
+ if (/^\[/.test(line.trim()) && inDeps) {
277
+ inDeps = false;
278
+ continue;
279
+ }
280
+ if (inDeps) {
281
+ const m = line.match(/^\s*([\w][\w-]*)\s*=/);
282
+ if (m)
283
+ deps.add(m[1].replace(/-/g, '_')); // Rust uses _ in code for - in Cargo
284
+ }
285
+ }
286
+ }
287
+ }
288
+ catch { /* no Cargo.toml */ }
289
+ return deps;
290
+ }
291
+ export function checkJavaKotlinImports(content, file, ext, cwd, projectFiles, hallucinated) {
292
+ const lines = content.split('\n');
293
+ const buildDeps = loadJavaDeps(cwd);
294
+ const isKotlin = ext === '.kt';
295
+ for (let i = 0; i < lines.length; i++) {
296
+ const line = lines[i].trim();
297
+ // import com.example.package.Class
298
+ const importMatch = line.match(/^import\s+(?:static\s+)?([\w.]+)/);
299
+ if (!importMatch)
300
+ continue;
301
+ const importPath = importMatch[1];
302
+ // Skip Java stdlib
303
+ if (isJavaStdlib(importPath))
304
+ continue;
305
+ // Skip Kotlin stdlib
306
+ if (isKotlin && isKotlinStdlib(importPath))
307
+ continue;
308
+ // Skip known build dependencies (by group prefix)
309
+ const parts = importPath.split('.');
310
+ const group2 = parts.slice(0, 2).join('.');
311
+ const group3 = parts.slice(0, 3).join('.');
312
+ if (buildDeps.has(group2) || buildDeps.has(group3))
313
+ continue;
314
+ // Check if it resolves to a project file
315
+ const javaPath = importPath.replace(/\./g, '/');
316
+ const candidates = [
317
+ javaPath + '.java',
318
+ javaPath + '.kt',
319
+ 'src/main/java/' + javaPath + '.java',
320
+ 'src/main/kotlin/' + javaPath + '.kt',
321
+ ];
322
+ const found = candidates.some(c => projectFiles.has(c)) ||
323
+ [...projectFiles].some(f => f.includes(javaPath));
324
+ if (!found) {
325
+ // Only flag if we have build deps context (Gradle/Maven project)
326
+ if (buildDeps.size > 0) {
327
+ hallucinated.push({
328
+ file, line: i + 1, importPath, type: isKotlin ? 'kotlin' : 'java',
329
+ reason: `import '${importPath}' — not in stdlib, build deps, or project files`,
330
+ });
331
+ }
332
+ }
333
+ }
334
+ }
335
+ export function loadJavaDeps(cwd) {
336
+ const deps = new Set();
337
+ try {
338
+ // Gradle: build.gradle or build.gradle.kts
339
+ for (const gradleFile of ['build.gradle', 'build.gradle.kts']) {
340
+ const gradlePath = path.join(cwd, gradleFile);
341
+ if (fs.pathExistsSync(gradlePath)) {
342
+ const content = fs.readFileSync(gradlePath, 'utf-8');
343
+ // Match: implementation 'group:artifact:version' or "group:artifact:version"
344
+ const depPattern = /(?:implementation|api|compile|testImplementation|runtimeOnly)\s*[('"]([^:'"]+)/g;
345
+ let m;
346
+ while ((m = depPattern.exec(content)) !== null) {
347
+ deps.add(m[1]); // group ID like "com.google.guava"
348
+ }
349
+ }
350
+ }
351
+ // Maven: pom.xml
352
+ const pomPath = path.join(cwd, 'pom.xml');
353
+ if (fs.pathExistsSync(pomPath)) {
354
+ const content = fs.readFileSync(pomPath, 'utf-8');
355
+ const groupPattern = /<groupId>([^<]+)<\/groupId>/g;
356
+ let m;
357
+ while ((m = groupPattern.exec(content)) !== null) {
358
+ deps.add(m[1]);
359
+ }
360
+ }
361
+ }
362
+ catch { /* no build files */ }
363
+ return deps;
364
+ }
365
+ export async function loadPackageJson(cwd) {
366
+ try {
367
+ const pkgPath = path.join(cwd, 'package.json');
368
+ if (await fs.pathExists(pkgPath)) {
369
+ return await fs.readJson(pkgPath);
370
+ }
371
+ }
372
+ catch (e) { }
373
+ return null;
374
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Standard library detection helpers for hallucinated-imports gate.
3
+ * Each function returns true if the given import path is part of that language's stdlib.
4
+ */
5
+ export declare function isNodeBuiltin(name: string): boolean;
6
+ export declare function isPythonStdlib(modulePath: string): boolean;
7
+ export declare function isGoStdlib(importPath: string): boolean;
8
+ export declare function isRubyStdlib(name: string): boolean;
9
+ export declare function isDotNetFramework(namespace: string): boolean;
10
+ export declare function isRustStdCrate(name: string): boolean;
11
+ export declare function isJavaStdlib(importPath: string): boolean;
12
+ export declare function isKotlinStdlib(importPath: string): boolean;
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Standard library detection helpers for hallucinated-imports gate.
3
+ * Each function returns true if the given import path is part of that language's stdlib.
4
+ */
5
+ export function isNodeBuiltin(name) {
6
+ // Fast path: node: protocol prefix
7
+ if (name.startsWith('node:'))
8
+ return true;
9
+ const builtins = new Set([
10
+ 'assert', 'assert/strict', 'async_hooks', 'buffer', 'child_process',
11
+ 'cluster', 'console', 'constants', 'crypto', 'dgram', 'diagnostics_channel',
12
+ 'dns', 'dns/promises', 'domain', 'events', 'fs', 'fs/promises',
13
+ 'http', 'http2', 'https', 'inspector', 'inspector/promises', 'module',
14
+ 'net', 'os', 'path', 'path/posix', 'path/win32', 'perf_hooks',
15
+ 'process', 'punycode', 'querystring', 'readline', 'readline/promises',
16
+ 'repl', 'stream', 'stream/consumers', 'stream/promises', 'stream/web',
17
+ 'string_decoder', 'sys', 'test', 'timers', 'timers/promises',
18
+ 'tls', 'trace_events', 'tty', 'url', 'util', 'util/types',
19
+ 'v8', 'vm', 'wasi', 'worker_threads', 'zlib',
20
+ ]);
21
+ return builtins.has(name);
22
+ }
23
+ export function isPythonStdlib(modulePath) {
24
+ const topLevel = modulePath.split('.')[0];
25
+ const stdlibs = new Set([
26
+ 'abc', 'aifc', 'argparse', 'array', 'ast', 'asyncio', 'atexit',
27
+ 'base64', 'bdb', 'binascii', 'binhex', 'bisect', 'builtins',
28
+ 'calendar', 'cgi', 'cgitb', 'chunk', 'cmath', 'cmd', 'code',
29
+ 'codecs', 'codeop', 'collections', 'colorsys', 'compileall',
30
+ 'concurrent', 'configparser', 'contextlib', 'contextvars', 'copy',
31
+ 'copyreg', 'cProfile', 'csv', 'ctypes', 'curses', 'dataclasses',
32
+ 'datetime', 'dbm', 'decimal', 'difflib', 'dis', 'distutils',
33
+ 'doctest', 'email', 'encodings', 'enum', 'errno', 'faulthandler',
34
+ 'fcntl', 'filecmp', 'fileinput', 'fnmatch', 'fractions', 'ftplib',
35
+ 'functools', 'gc', 'getopt', 'getpass', 'gettext', 'glob', 'grp',
36
+ 'gzip', 'hashlib', 'heapq', 'hmac', 'html', 'http', 'idlelib',
37
+ 'imaplib', 'imghdr', 'importlib', 'inspect', 'io', 'ipaddress',
38
+ 'itertools', 'json', 'keyword', 'lib2to3', 'linecache', 'locale',
39
+ 'logging', 'lzma', 'mailbox', 'mailcap', 'marshal', 'math',
40
+ 'mimetypes', 'mmap', 'modulefinder', 'multiprocessing', 'netrc',
41
+ 'nis', 'nntplib', 'numbers', 'operator', 'optparse', 'os',
42
+ 'ossaudiodev', 'parser', 'pathlib', 'pdb', 'pickle', 'pickletools',
43
+ 'pipes', 'pkgutil', 'platform', 'plistlib', 'poplib', 'posix',
44
+ 'posixpath', 'pprint', 'profile', 'pstats', 'pty', 'pwd', 'py_compile',
45
+ 'pyclbr', 'pydoc', 'queue', 'quopri', 'random', 're', 'readline',
46
+ 'reprlib', 'resource', 'rlcompleter', 'runpy', 'sched', 'secrets',
47
+ 'select', 'selectors', 'shelve', 'shlex', 'shutil', 'signal',
48
+ 'site', 'smtpd', 'smtplib', 'sndhdr', 'socket', 'socketserver',
49
+ 'spwd', 'sqlite3', 'sre_compile', 'sre_constants', 'sre_parse',
50
+ 'ssl', 'stat', 'statistics', 'string', 'stringprep', 'struct',
51
+ 'subprocess', 'sunau', 'symtable', 'sys', 'sysconfig', 'syslog',
52
+ 'tabnanny', 'tarfile', 'telnetlib', 'tempfile', 'termios', 'test',
53
+ 'textwrap', 'threading', 'time', 'timeit', 'tkinter', 'token',
54
+ 'tokenize', 'tomllib', 'trace', 'traceback', 'tracemalloc', 'tty',
55
+ 'turtle', 'turtledemo', 'types', 'typing', 'unicodedata', 'unittest',
56
+ 'urllib', 'uu', 'uuid', 'venv', 'warnings', 'wave', 'weakref',
57
+ 'webbrowser', 'winreg', 'winsound', 'wsgiref', 'xdrlib', 'xml',
58
+ 'xmlrpc', 'zipapp', 'zipfile', 'zipimport', 'zlib',
59
+ '_thread', '__future__', '__main__',
60
+ ]);
61
+ return stdlibs.has(topLevel);
62
+ }
63
+ export function isGoStdlib(importPath) {
64
+ // Fast check: single-segment packages are always stdlib if no dots
65
+ if (!importPath.includes('/') && !importPath.includes('.'))
66
+ return true;
67
+ // Check the full path against known stdlib packages with sub-paths
68
+ const topLevel = importPath.split('/')[0];
69
+ // All Go stdlib top-level packages (including those with sub-packages)
70
+ const stdlibTopLevel = new Set([
71
+ // Single-word packages
72
+ 'archive', 'bufio', 'builtin', 'bytes', 'cmp', 'compress',
73
+ 'container', 'context', 'crypto', 'database', 'debug',
74
+ 'embed', 'encoding', 'errors', 'expvar', 'flag', 'fmt',
75
+ 'go', 'hash', 'html', 'image', 'index', 'io', 'iter',
76
+ 'log', 'maps', 'math', 'mime', 'net', 'os', 'path',
77
+ 'plugin', 'reflect', 'regexp', 'runtime', 'slices', 'sort',
78
+ 'strconv', 'strings', 'structs', 'sync', 'syscall',
79
+ 'testing', 'text', 'time', 'unicode', 'unique', 'unsafe',
80
+ // Internal packages (used by stdlib, sometimes by tools)
81
+ 'internal', 'vendor',
82
+ ]);
83
+ if (stdlibTopLevel.has(topLevel))
84
+ return true;
85
+ // Explicit full-path list for maximum safety — covers all Go 1.22 stdlib paths
86
+ // This catches any edge case the top-level check might miss
87
+ const knownStdlibPaths = new Set([
88
+ // archive/*
89
+ 'archive/tar', 'archive/zip',
90
+ // compress/*
91
+ 'compress/bzip2', 'compress/flate', 'compress/gzip', 'compress/lzw', 'compress/zlib',
92
+ // container/*
93
+ 'container/heap', 'container/list', 'container/ring',
94
+ // crypto/*
95
+ 'crypto/aes', 'crypto/cipher', 'crypto/des', 'crypto/dsa',
96
+ 'crypto/ecdh', 'crypto/ecdsa', 'crypto/ed25519', 'crypto/elliptic',
97
+ 'crypto/hmac', 'crypto/md5', 'crypto/rand', 'crypto/rc4',
98
+ 'crypto/rsa', 'crypto/sha1', 'crypto/sha256', 'crypto/sha512',
99
+ 'crypto/subtle', 'crypto/tls', 'crypto/x509', 'crypto/x509/pkix',
100
+ // database/*
101
+ 'database/sql', 'database/sql/driver',
102
+ // debug/*
103
+ 'debug/buildinfo', 'debug/dwarf', 'debug/elf', 'debug/gosym',
104
+ 'debug/macho', 'debug/pe', 'debug/plan9obj',
105
+ // encoding/*
106
+ 'encoding/ascii85', 'encoding/asn1', 'encoding/base32', 'encoding/base64',
107
+ 'encoding/binary', 'encoding/csv', 'encoding/gob', 'encoding/hex',
108
+ 'encoding/json', 'encoding/pem', 'encoding/xml',
109
+ // go/*
110
+ 'go/ast', 'go/build', 'go/build/constraint', 'go/constant',
111
+ 'go/doc', 'go/doc/comment', 'go/format', 'go/importer',
112
+ 'go/parser', 'go/printer', 'go/scanner', 'go/token', 'go/types', 'go/version',
113
+ // hash/*
114
+ 'hash/adler32', 'hash/crc32', 'hash/crc64', 'hash/fnv', 'hash/maphash',
115
+ // html/*
116
+ 'html/template',
117
+ // image/*
118
+ 'image/color', 'image/color/palette', 'image/draw',
119
+ 'image/gif', 'image/jpeg', 'image/png',
120
+ // index/*
121
+ 'index/suffixarray',
122
+ // io/*
123
+ 'io/fs', 'io/ioutil',
124
+ // log/*
125
+ 'log/slog', 'log/syslog',
126
+ // math/*
127
+ 'math/big', 'math/bits', 'math/cmplx', 'math/rand', 'math/rand/v2',
128
+ // mime/*
129
+ 'mime/multipart', 'mime/quotedprintable',
130
+ // net/*
131
+ 'net/http', 'net/http/cgi', 'net/http/cookiejar', 'net/http/fcgi',
132
+ 'net/http/httptest', 'net/http/httptrace', 'net/http/httputil',
133
+ 'net/http/pprof', 'net/mail', 'net/netip', 'net/rpc',
134
+ 'net/rpc/jsonrpc', 'net/smtp', 'net/textproto', 'net/url',
135
+ // os/*
136
+ 'os/exec', 'os/signal', 'os/user',
137
+ // path/*
138
+ 'path/filepath',
139
+ // regexp/*
140
+ 'regexp/syntax',
141
+ // runtime/*
142
+ 'runtime/cgo', 'runtime/coverage', 'runtime/debug', 'runtime/metrics',
143
+ 'runtime/pprof', 'runtime/race', 'runtime/trace',
144
+ // sync/*
145
+ 'sync/atomic',
146
+ // testing/*
147
+ 'testing/fstest', 'testing/iotest', 'testing/quick', 'testing/slogtest',
148
+ // text/*
149
+ 'text/scanner', 'text/tabwriter', 'text/template', 'text/template/parse',
150
+ // unicode/*
151
+ 'unicode/utf16', 'unicode/utf8',
152
+ ]);
153
+ return knownStdlibPaths.has(importPath);
154
+ }
155
+ export function isRubyStdlib(name) {
156
+ const topLevel = name.split('/')[0];
157
+ const stdlibs = new Set([
158
+ // Core libs (always available)
159
+ 'abbrev', 'base64', 'benchmark', 'bigdecimal', 'cgi', 'csv',
160
+ 'date', 'delegate', 'did_you_mean', 'digest', 'drb', 'english',
161
+ 'erb', 'error_highlight', 'etc', 'fcntl', 'fiddle', 'fileutils',
162
+ 'find', 'forwardable', 'getoptlong', 'io', 'ipaddr', 'irb',
163
+ 'json', 'logger', 'matrix', 'minitest', 'monitor', 'mutex_m',
164
+ 'net', 'nkf', 'objspace', 'observer', 'open3', 'open-uri',
165
+ 'openssl', 'optparse', 'ostruct', 'pathname', 'pp', 'prettyprint',
166
+ 'prime', 'pstore', 'psych', 'racc', 'rake', 'rdoc', 'readline',
167
+ 'reline', 'resolv', 'resolv-replace', 'rinda', 'ruby2_keywords',
168
+ 'rubygems', 'securerandom', 'set', 'shellwords', 'singleton',
169
+ 'socket', 'stringio', 'strscan', 'syntax_suggest', 'syslog',
170
+ 'tempfile', 'time', 'timeout', 'tmpdir', 'tsort', 'un',
171
+ 'unicode_normalize', 'uri', 'weakref', 'yaml', 'zlib',
172
+ // Default gems (ship with Ruby, can be overridden)
173
+ 'bundler', 'debug', 'net-ftp', 'net-http', 'net-imap',
174
+ 'net-pop', 'net-protocol', 'net-smtp', 'power_assert',
175
+ 'test-unit', 'rexml', 'rss', 'typeprof',
176
+ // Common C extensions
177
+ 'stringio', 'io/console', 'io/nonblock', 'io/wait',
178
+ 'rbconfig', 'mkmf', 'thread',
179
+ // Rails-adjacent but actually stdlib
180
+ 'webrick', 'cmath', 'complex', 'rational',
181
+ 'coverage', 'ripper', 'win32ole', 'win32api',
182
+ ]);
183
+ return stdlibs.has(topLevel);
184
+ }
185
+ export function isDotNetFramework(namespace) {
186
+ const topLevel = namespace.split('.')[0];
187
+ const frameworkPrefixes = new Set([
188
+ // BCL / .NET Runtime
189
+ 'System', 'Microsoft', 'Windows',
190
+ // Common ecosystem (NuGet defaults everyone uses)
191
+ 'Newtonsoft', 'NUnit', 'Xunit', 'Moq', 'AutoMapper',
192
+ 'FluentAssertions', 'FluentValidation', 'Serilog', 'NLog',
193
+ 'Dapper', 'MediatR', 'Polly', 'Swashbuckle', 'Hangfire',
194
+ 'StackExchange', 'Npgsql', 'MongoDB', 'MySql', 'Oracle',
195
+ 'Amazon', 'Google', 'Azure', 'Grpc',
196
+ 'Bogus', 'Humanizer', 'CsvHelper', 'MailKit', 'MimeKit',
197
+ 'RestSharp', 'Refit', 'AutoFixture', 'Shouldly',
198
+ 'IdentityModel', 'IdentityServer4',
199
+ ]);
200
+ return frameworkPrefixes.has(topLevel);
201
+ }
202
+ export function isRustStdCrate(name) {
203
+ const stdCrates = new Set([
204
+ 'std', 'core', 'alloc', 'proc_macro', 'test',
205
+ // Common proc-macro / compiler crates
206
+ 'proc_macro2', 'syn', 'quote',
207
+ ]);
208
+ return stdCrates.has(name);
209
+ }
210
+ export function isJavaStdlib(importPath) {
211
+ const prefixes = [
212
+ 'java.', 'javax.', 'jakarta.',
213
+ 'sun.', 'com.sun.', 'jdk.',
214
+ // Android SDK
215
+ 'android.', 'androidx.',
216
+ // Common ecosystem (so ubiquitous they're basically stdlib)
217
+ 'org.junit.', 'org.slf4j.', 'org.apache.logging.',
218
+ ];
219
+ return prefixes.some(p => importPath.startsWith(p));
220
+ }
221
+ export function isKotlinStdlib(importPath) {
222
+ const prefixes = [
223
+ 'kotlin.', 'kotlinx.',
224
+ // Java interop (Kotlin can use Java stdlib directly)
225
+ 'java.', 'javax.', 'jakarta.',
226
+ ];
227
+ return prefixes.some(p => importPath.startsWith(p));
228
+ }