@rigour-labs/core 3.0.5 → 3.0.6

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 (47) hide show
  1. package/dist/gates/deprecated-apis-rules-lang.d.ts +21 -0
  2. package/dist/gates/deprecated-apis-rules-lang.js +311 -0
  3. package/dist/gates/deprecated-apis-rules-node.d.ts +19 -0
  4. package/dist/gates/deprecated-apis-rules-node.js +199 -0
  5. package/dist/gates/deprecated-apis-rules.d.ts +6 -0
  6. package/dist/gates/deprecated-apis-rules.js +6 -0
  7. package/dist/gates/deprecated-apis.js +1 -502
  8. package/dist/gates/hallucinated-imports-lang.d.ts +16 -0
  9. package/dist/gates/hallucinated-imports-lang.js +374 -0
  10. package/dist/gates/hallucinated-imports-stdlib.d.ts +12 -0
  11. package/dist/gates/hallucinated-imports-stdlib.js +228 -0
  12. package/dist/gates/hallucinated-imports.d.ts +0 -98
  13. package/dist/gates/hallucinated-imports.js +10 -678
  14. package/dist/gates/phantom-apis-data.d.ts +33 -0
  15. package/dist/gates/phantom-apis-data.js +398 -0
  16. package/dist/gates/phantom-apis.js +1 -393
  17. package/dist/gates/phantom-apis.test.js +52 -0
  18. package/dist/gates/promise-safety-helpers.d.ts +19 -0
  19. package/dist/gates/promise-safety-helpers.js +101 -0
  20. package/dist/gates/promise-safety-rules.d.ts +7 -0
  21. package/dist/gates/promise-safety-rules.js +19 -0
  22. package/dist/gates/promise-safety.d.ts +1 -21
  23. package/dist/gates/promise-safety.js +51 -257
  24. package/dist/gates/test-quality-lang.d.ts +30 -0
  25. package/dist/gates/test-quality-lang.js +188 -0
  26. package/dist/gates/test-quality.d.ts +0 -14
  27. package/dist/gates/test-quality.js +13 -186
  28. package/dist/pattern-index/indexer-helpers.d.ts +38 -0
  29. package/dist/pattern-index/indexer-helpers.js +111 -0
  30. package/dist/pattern-index/indexer-lang.d.ts +13 -0
  31. package/dist/pattern-index/indexer-lang.js +244 -0
  32. package/dist/pattern-index/indexer-ts.d.ts +22 -0
  33. package/dist/pattern-index/indexer-ts.js +258 -0
  34. package/dist/pattern-index/indexer.d.ts +4 -106
  35. package/dist/pattern-index/indexer.js +58 -707
  36. package/dist/pattern-index/staleness-data.d.ts +6 -0
  37. package/dist/pattern-index/staleness-data.js +262 -0
  38. package/dist/pattern-index/staleness.js +1 -258
  39. package/dist/templates/index.d.ts +12 -16
  40. package/dist/templates/index.js +11 -527
  41. package/dist/templates/paradigms.d.ts +2 -0
  42. package/dist/templates/paradigms.js +46 -0
  43. package/dist/templates/presets.d.ts +14 -0
  44. package/dist/templates/presets.js +227 -0
  45. package/dist/templates/universal-config.d.ts +2 -0
  46. package/dist/templates/universal-config.js +171 -0
  47. package/package.json +1 -1
@@ -24,6 +24,7 @@ import { FileScanner } from '../utils/scanner.js';
24
24
  import { Logger } from '../utils/logger.js';
25
25
  import fs from 'fs-extra';
26
26
  import path from 'path';
27
+ import { GO_PHANTOM_RULES, CSHARP_PHANTOM_RULES, JAVA_PHANTOM_RULES, NODE_STDLIB_METHODS, PYTHON_STDLIB_METHODS } from './phantom-apis-data.js';
27
28
  export class PhantomApisGate extends Gate {
28
29
  config;
29
30
  constructor(config = {}) {
@@ -280,396 +281,3 @@ export class PhantomApisGate extends Gate {
280
281
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
281
282
  }
282
283
  }
283
- /**
284
- * Go commonly hallucinated APIs — AI mixes up Python/JS idioms with Go.
285
- */
286
- const GO_PHANTOM_RULES = [
287
- { pattern: /\bstrings\.includes\s*\(/, module: 'strings', phantom: 'includes', suggestion: "Use strings.Contains()" },
288
- { pattern: /\bstrings\.lower\s*\(/, module: 'strings', phantom: 'lower', suggestion: "Use strings.ToLower()" },
289
- { pattern: /\bstrings\.upper\s*\(/, module: 'strings', phantom: 'upper', suggestion: "Use strings.ToUpper()" },
290
- { pattern: /\bstrings\.strip\s*\(/, module: 'strings', phantom: 'strip', suggestion: "Use strings.TrimSpace()" },
291
- { pattern: /\bstrings\.find\s*\(/, module: 'strings', phantom: 'find', suggestion: "Use strings.Index()" },
292
- { pattern: /\bstrings\.startswith\s*\(/, module: 'strings', phantom: 'startswith', suggestion: "Use strings.HasPrefix()" },
293
- { pattern: /\bstrings\.endswith\s*\(/, module: 'strings', phantom: 'endswith', suggestion: "Use strings.HasSuffix()" },
294
- { pattern: /\bos\.ReadFile\s*\(/, module: 'os', phantom: 'ReadFile', suggestion: "Use os.ReadFile() (Go 1.16+) or ioutil.ReadFile() (legacy)" },
295
- { pattern: /\bos\.Exists\s*\(/, module: 'os', phantom: 'Exists', suggestion: "Use os.Stat() and check os.IsNotExist(err)" },
296
- { pattern: /\bos\.isdir\s*\(/, module: 'os', phantom: 'isdir', suggestion: "Use os.Stat() then .IsDir()" },
297
- { pattern: /\bos\.listdir\s*\(/, module: 'os', phantom: 'listdir', suggestion: "Use os.ReadDir()" },
298
- { pattern: /\bfmt\.Format\s*\(/, module: 'fmt', phantom: 'Format', suggestion: "Use fmt.Sprintf()" },
299
- { pattern: /\bfmt\.Print\s*\((?!ln|f)/, module: 'fmt', phantom: 'Print', suggestion: "fmt.Print() exists but did you mean fmt.Println() or fmt.Printf()?" },
300
- { pattern: /\bhttp\.Get\s*\([^)]*\)\s*\.\s*Body/, module: 'http', phantom: 'Get().Body', suggestion: "http.Get() returns (*Response, error) — must check error first" },
301
- { pattern: /\bjson\.parse\s*\(/, module: 'json', phantom: 'parse', suggestion: "Use json.Unmarshal()" },
302
- { pattern: /\bjson\.stringify\s*\(/, module: 'json', phantom: 'stringify', suggestion: "Use json.Marshal()" },
303
- { pattern: /\bfilepath\.Combine\s*\(/, module: 'filepath', phantom: 'Combine', suggestion: "Use filepath.Join()" },
304
- { pattern: /\bmath\.Max\s*\(/, module: 'math', phantom: 'Max (pre-1.21)', suggestion: "math.Max() only works on float64. For int, use max() builtin (Go 1.21+)" },
305
- { pattern: /\bsort\.Sort\s*\(\s*\[\]/, module: 'sort', phantom: 'Sort([]T)', suggestion: "Use slices.Sort() (Go 1.21+) or sort.Slice()" },
306
- ];
307
- /**
308
- * C# commonly hallucinated APIs — AI mixes up Java/Python idioms with .NET.
309
- */
310
- const CSHARP_PHANTOM_RULES = [
311
- { pattern: /\.length\b(?!\s*\()/, module: 'String', phantom: '.length', suggestion: "Use .Length (capital L) in C#" },
312
- { pattern: /\.equals\s*\(/, module: 'Object', phantom: '.equals()', suggestion: "Use .Equals() (capital E) in C#" },
313
- { pattern: /\.toString\s*\(/, module: 'Object', phantom: '.toString()', suggestion: "Use .ToString() (capital T) in C#" },
314
- { pattern: /\.hashCode\s*\(/, module: 'Object', phantom: '.hashCode()', suggestion: "Use .GetHashCode() in C#" },
315
- { pattern: /\.getClass\s*\(/, module: 'Object', phantom: '.getClass()', suggestion: "Use .GetType() in C#" },
316
- { pattern: /\.isEmpty\s*\(/, module: 'String', phantom: '.isEmpty()', suggestion: "Use string.IsNullOrEmpty() or .Length == 0 in C#" },
317
- { pattern: /\.charAt\s*\(/, module: 'String', phantom: '.charAt()', suggestion: "Use string[index] indexer in C#" },
318
- { pattern: /\.substring\s*\(/, module: 'String', phantom: '.substring()', suggestion: "Use .Substring() (capital S) in C#" },
319
- { pattern: /\.indexOf\s*\(/, module: 'String', phantom: '.indexOf()', suggestion: "Use .IndexOf() (capital I) in C#" },
320
- { pattern: /List<[^>]+>\s+\w+\s*=\s*new\s+ArrayList/, module: 'Collections', phantom: 'ArrayList', suggestion: "Use new List<T>() in C# — ArrayList is Java" },
321
- { pattern: /HashMap</, module: 'Collections', phantom: 'HashMap', suggestion: "Use Dictionary<TKey, TValue> in C#" },
322
- { pattern: /System\.out\.println/, module: 'System', phantom: 'System.out.println', suggestion: "Use Console.WriteLine() in C#" },
323
- { pattern: /\.stream\s*\(\)\s*\./, module: 'Collections', phantom: '.stream()', suggestion: "Use LINQ (.Select, .Where, etc.) in C# — .stream() is Java" },
324
- { pattern: /\.forEach\s*\(\s*\w+\s*->/, module: 'Collections', phantom: '.forEach(x ->)', suggestion: "Use .ForEach(x =>) or foreach loop in C#" },
325
- { pattern: /File\.readAllText\s*\(/, module: 'File', phantom: 'readAllText', suggestion: "Use File.ReadAllText() (capital R) in C#" },
326
- { pattern: /throws\s+\w+Exception/, module: 'method', phantom: 'throws', suggestion: "C# doesn't use checked exceptions — remove throws clause" },
327
- ];
328
- /**
329
- * Java commonly hallucinated APIs — AI mixes up Python/JS/C# idioms with JDK.
330
- */
331
- const JAVA_PHANTOM_RULES = [
332
- { pattern: /\.len\s*\(/, module: 'Object', phantom: '.len()', suggestion: "Use .length() for String, .size() for Collection, .length for arrays in Java" },
333
- { pattern: /\bprint\s*\(\s*['"]/, module: 'IO', phantom: 'print()', suggestion: "Use System.out.println() in Java" },
334
- { pattern: /\.push\s*\(/, module: 'List', phantom: '.push()', suggestion: "Use .add() for List in Java" },
335
- { pattern: /\.append\s*\((?!.*StringBuilder|.*StringBuffer)/, module: 'List', phantom: '.append()', suggestion: "Use .add() for List in Java — .append() is for StringBuilder" },
336
- { pattern: /\.include(?:s)?\s*\(/, module: 'Collection', phantom: '.includes()', suggestion: "Use .contains() in Java" },
337
- { pattern: /\.slice\s*\(/, module: 'List', phantom: '.slice()', suggestion: "Use .subList() for List in Java" },
338
- { pattern: /\.map\s*\(\s*\w+\s*=>/, module: 'Collection', phantom: '.map(x =>)', suggestion: "Use .stream().map(x ->) in Java — arrow is -> not =>" },
339
- { pattern: /\.filter\s*\(\s*\w+\s*=>/, module: 'Collection', phantom: '.filter(x =>)', suggestion: "Use .stream().filter(x ->) in Java — arrow is -> not =>" },
340
- { pattern: /Console\.(?:Write|Read)/, module: 'IO', phantom: 'Console', suggestion: "Console is C# — use System.out.println() or Scanner in Java" },
341
- { pattern: /\bvar\s+\w+\s*:\s*\w+\s*=/, module: 'syntax', phantom: 'var x: Type =', suggestion: "Java var doesn't use type annotation: use 'var x =' or 'Type x ='" },
342
- { pattern: /\.sorted\s*\(\s*\)(?!\s*\.)/, module: 'List', phantom: '.sorted()', suggestion: "Use Collections.sort() or .stream().sorted() in Java" },
343
- { pattern: /\.reversed\s*\(/, module: 'List', phantom: '.reversed()', suggestion: "Use Collections.reverse() in Java (pre-21) or .reversed() (Java 21+)" },
344
- { pattern: /String\.format\s*\(\s*\$"/, module: 'String', phantom: 'String.format($"...")', suggestion: "String interpolation $\"\" is C# — use String.format(\"%s\", ...) in Java" },
345
- { pattern: /\bnew\s+Map\s*[<(]/, module: 'Collections', phantom: 'new Map()', suggestion: "Use new HashMap<>() in Java — Map is an interface" },
346
- { pattern: /\bnew\s+List\s*[<(]/, module: 'Collections', phantom: 'new List()', suggestion: "Use new ArrayList<>() in Java — List is an interface" },
347
- ];
348
- /**
349
- * Node.js 22.x stdlib method signatures.
350
- * Only the most commonly hallucinated modules are covered.
351
- * Each set contains ALL public methods/properties accessible on the module.
352
- */
353
- const NODE_STDLIB_METHODS = {
354
- fs: new Set([
355
- // Sync methods
356
- 'readFileSync', 'writeFileSync', 'appendFileSync', 'copyFileSync', 'renameSync',
357
- 'unlinkSync', 'mkdirSync', 'rmdirSync', 'rmSync', 'readdirSync', 'statSync',
358
- 'lstatSync', 'existsSync', 'accessSync', 'chmodSync', 'chownSync', 'closeSync',
359
- 'fchmodSync', 'fchownSync', 'fdatasyncSync', 'fstatSync', 'fsyncSync',
360
- 'ftruncateSync', 'futimesSync', 'linkSync', 'lutimesSync', 'mkdtempSync',
361
- 'openSync', 'opendirSync', 'readSync', 'readlinkSync', 'realpathSync',
362
- 'symlinkSync', 'truncateSync', 'utimesSync', 'writeSync', 'cpSync',
363
- 'statfsSync', 'globSync',
364
- // Async callback methods
365
- 'readFile', 'writeFile', 'appendFile', 'copyFile', 'rename', 'unlink',
366
- 'mkdir', 'rmdir', 'rm', 'readdir', 'stat', 'lstat', 'access', 'chmod',
367
- 'chown', 'close', 'fchmod', 'fchown', 'fdatasync', 'fstat', 'fsync',
368
- 'ftruncate', 'futimes', 'link', 'lutimes', 'mkdtemp', 'open', 'opendir',
369
- 'read', 'readlink', 'realpath', 'symlink', 'truncate', 'utimes', 'write',
370
- 'cp', 'statfs', 'glob',
371
- // Streams
372
- 'createReadStream', 'createWriteStream',
373
- // Watch
374
- 'watch', 'watchFile', 'unwatchFile',
375
- // Constants & promises
376
- 'constants', 'promises',
377
- ]),
378
- path: new Set([
379
- 'basename', 'delimiter', 'dirname', 'extname', 'format', 'isAbsolute',
380
- 'join', 'normalize', 'parse', 'posix', 'relative', 'resolve', 'sep',
381
- 'toNamespacedPath', 'win32', 'matchesGlob',
382
- ]),
383
- crypto: new Set([
384
- 'createHash', 'createHmac', 'createCipheriv', 'createDecipheriv',
385
- 'createSign', 'createVerify', 'createDiffieHellman', 'createDiffieHellmanGroup',
386
- 'createECDH', 'createSecretKey', 'createPublicKey', 'createPrivateKey',
387
- 'generateKey', 'generateKeyPair', 'generateKeyPairSync', 'generateKeySync',
388
- 'generatePrime', 'generatePrimeSync',
389
- 'getCiphers', 'getCurves', 'getDiffieHellman', 'getFips', 'getHashes',
390
- 'getRandomValues', 'hash',
391
- 'hkdf', 'hkdfSync',
392
- 'pbkdf2', 'pbkdf2Sync',
393
- 'privateDecrypt', 'privateEncrypt', 'publicDecrypt', 'publicEncrypt',
394
- 'randomBytes', 'randomFillSync', 'randomFill', 'randomInt', 'randomUUID',
395
- 'scrypt', 'scryptSync',
396
- 'setEngine', 'setFips',
397
- 'sign', 'verify',
398
- 'subtle', 'timingSafeEqual',
399
- 'constants', 'webcrypto', 'X509Certificate',
400
- 'checkPrime', 'checkPrimeSync',
401
- 'Certificate', 'Cipher', 'Decipher', 'DiffieHellman', 'DiffieHellmanGroup',
402
- 'ECDH', 'Hash', 'Hmac', 'KeyObject', 'Sign', 'Verify',
403
- ]),
404
- os: new Set([
405
- 'arch', 'availableParallelism', 'constants', 'cpus', 'devNull',
406
- 'endianness', 'EOL', 'freemem', 'getPriority', 'homedir',
407
- 'hostname', 'loadavg', 'machine', 'networkInterfaces', 'platform',
408
- 'release', 'setPriority', 'tmpdir', 'totalmem', 'type',
409
- 'uptime', 'userInfo', 'version',
410
- ]),
411
- child_process: new Set([
412
- 'exec', 'execFile', 'execFileSync', 'execSync',
413
- 'fork', 'spawn', 'spawnSync',
414
- ]),
415
- http: new Set([
416
- 'createServer', 'get', 'globalAgent', 'request',
417
- 'Agent', 'ClientRequest', 'Server', 'ServerResponse', 'IncomingMessage',
418
- 'METHODS', 'STATUS_CODES', 'maxHeaderSize', 'validateHeaderName', 'validateHeaderValue',
419
- 'setMaxIdleHTTPParsers',
420
- ]),
421
- https: new Set([
422
- 'createServer', 'get', 'globalAgent', 'request',
423
- 'Agent', 'Server',
424
- ]),
425
- url: new Set([
426
- 'domainToASCII', 'domainToUnicode', 'fileURLToPath', 'format',
427
- 'pathToFileURL', 'resolve', 'URL', 'URLSearchParams',
428
- // Deprecated but still exist
429
- 'parse', 'Url',
430
- ]),
431
- util: new Set([
432
- 'callbackify', 'debuglog', 'deprecate', 'format', 'formatWithOptions',
433
- 'getSystemErrorName', 'getSystemErrorMap', 'inherits', 'inspect',
434
- 'isDeepStrictEqual', 'parseArgs', 'parseEnv', 'promisify',
435
- 'stripVTControlCharacters', 'styleText',
436
- 'TextDecoder', 'TextEncoder', 'MIMEType', 'MIMEParams',
437
- 'types', 'toUSVString', 'transferableAbortController', 'transferableAbortSignal',
438
- 'aborted',
439
- ]),
440
- stream: new Set([
441
- 'Readable', 'Writable', 'Duplex', 'Transform', 'PassThrough',
442
- 'pipeline', 'finished', 'compose', 'addAbortSignal',
443
- 'getDefaultHighWaterMark', 'setDefaultHighWaterMark',
444
- 'promises', 'consumers',
445
- ]),
446
- events: new Set([
447
- 'EventEmitter', 'once', 'on', 'getEventListeners',
448
- 'setMaxListeners', 'listenerCount', 'addAbortListener',
449
- 'getMaxListeners', 'EventEmitterAsyncResource',
450
- ]),
451
- buffer: new Set([
452
- 'Buffer', 'SlowBuffer', 'transcode',
453
- 'constants', 'kMaxLength', 'kStringMaxLength',
454
- 'atob', 'btoa', 'isAscii', 'isUtf8', 'resolveObjectURL',
455
- 'Blob', 'File',
456
- ]),
457
- querystring: new Set([
458
- 'decode', 'encode', 'escape', 'parse', 'stringify', 'unescape',
459
- ]),
460
- net: new Set([
461
- 'createServer', 'createConnection', 'connect',
462
- 'isIP', 'isIPv4', 'isIPv6',
463
- 'Server', 'Socket', 'BlockList', 'SocketAddress',
464
- 'getDefaultAutoSelectFamily', 'setDefaultAutoSelectFamily',
465
- 'getDefaultAutoSelectFamilyAttemptTimeout', 'setDefaultAutoSelectFamilyAttemptTimeout',
466
- ]),
467
- dns: new Set([
468
- 'lookup', 'lookupService', 'resolve', 'resolve4', 'resolve6',
469
- 'resolveAny', 'resolveCname', 'resolveCaa', 'resolveMx', 'resolveNaptr',
470
- 'resolveNs', 'resolvePtr', 'resolveSoa', 'resolveSrv', 'resolveTxt',
471
- 'reverse', 'setServers', 'getServers', 'setDefaultResultOrder',
472
- 'getDefaultResultOrder',
473
- 'promises', 'Resolver', 'ADDRCONFIG', 'V4MAPPED', 'ALL',
474
- ]),
475
- tls: new Set([
476
- 'createServer', 'connect', 'createSecureContext', 'createSecurePair',
477
- 'getCiphers', 'rootCertificates', 'DEFAULT_ECDH_CURVE', 'DEFAULT_MAX_VERSION',
478
- 'DEFAULT_MIN_VERSION', 'DEFAULT_CIPHERS',
479
- 'Server', 'TLSSocket', 'SecureContext',
480
- ]),
481
- zlib: new Set([
482
- 'createGzip', 'createGunzip', 'createDeflate', 'createInflate',
483
- 'createDeflateRaw', 'createInflateRaw', 'createBrotliCompress',
484
- 'createBrotliDecompress', 'createUnzip',
485
- 'gzip', 'gunzip', 'deflate', 'inflate', 'deflateRaw', 'inflateRaw',
486
- 'brotliCompress', 'brotliDecompress', 'unzip',
487
- 'gzipSync', 'gunzipSync', 'deflateSync', 'inflateSync',
488
- 'deflateRawSync', 'inflateRawSync', 'brotliCompressSync',
489
- 'brotliDecompressSync', 'unzipSync',
490
- 'constants',
491
- ]),
492
- readline: new Set([
493
- 'createInterface', 'clearLine', 'clearScreenDown', 'cursorTo',
494
- 'moveCursor', 'emitKeypressEvents',
495
- 'Interface', 'InterfaceConstructor', 'promises',
496
- ]),
497
- cluster: new Set([
498
- 'disconnect', 'fork', 'isMaster', 'isPrimary', 'isWorker',
499
- 'schedulingPolicy', 'settings', 'setupMaster', 'setupPrimary',
500
- 'worker', 'workers',
501
- 'Worker', 'SCHED_NONE', 'SCHED_RR',
502
- ]),
503
- worker_threads: new Set([
504
- 'isMainThread', 'parentPort', 'resourceLimits', 'threadId',
505
- 'workerData', 'getEnvironmentData', 'setEnvironmentData',
506
- 'markAsUntransferable', 'moveMessagePortToContext', 'receiveMessageOnPort',
507
- 'BroadcastChannel', 'MessageChannel', 'MessagePort', 'Worker',
508
- 'SHARE_ENV',
509
- ]),
510
- timers: new Set([
511
- 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval',
512
- 'setImmediate', 'clearImmediate',
513
- 'promises',
514
- ]),
515
- perf_hooks: new Set([
516
- 'performance', 'PerformanceObserver', 'PerformanceEntry',
517
- 'PerformanceMark', 'PerformanceMeasure', 'PerformanceNodeTiming',
518
- 'PerformanceResourceTiming', 'monitorEventLoopDelay',
519
- 'createHistogram',
520
- ]),
521
- assert: new Set([
522
- 'ok', 'fail', 'equal', 'notEqual', 'deepEqual', 'notDeepEqual',
523
- 'deepStrictEqual', 'notDeepStrictEqual', 'strictEqual', 'notStrictEqual',
524
- 'throws', 'doesNotThrow', 'rejects', 'doesNotReject',
525
- 'ifError', 'match', 'doesNotMatch',
526
- 'strict', 'AssertionError', 'CallTracker',
527
- ]),
528
- };
529
- /**
530
- * Python 3.12+ stdlib method signatures.
531
- * Covers the most commonly hallucinated modules.
532
- */
533
- const PYTHON_STDLIB_METHODS = {
534
- os: new Set([
535
- 'getcwd', 'chdir', 'listdir', 'scandir', 'mkdir', 'makedirs',
536
- 'rmdir', 'removedirs', 'remove', 'unlink', 'rename', 'renames',
537
- 'replace', 'stat', 'lstat', 'fstat', 'chmod', 'chown', 'link',
538
- 'symlink', 'readlink', 'walk', 'fwalk', 'path', 'environ',
539
- 'getenv', 'putenv', 'unsetenv', 'getpid', 'getppid', 'getuid',
540
- 'getgid', 'system', 'popen', 'execv', 'execve', 'execvp',
541
- 'execvpe', '_exit', 'fork', 'kill', 'wait', 'waitpid',
542
- 'cpu_count', 'urandom', 'sep', 'linesep', 'devnull', 'curdir',
543
- 'pardir', 'extsep', 'altsep', 'pathsep', 'name', 'access',
544
- 'open', 'close', 'read', 'write', 'pipe', 'dup', 'dup2',
545
- 'ftruncate', 'isatty', 'lseek', 'terminal_size', 'get_terminal_size',
546
- 'get_blocking', 'set_blocking', 'add_dll_directory',
547
- 'get_exec_path', 'getlogin', 'strerror', 'umask',
548
- 'truncate', 'fchdir', 'fchmod', 'fchown',
549
- ]),
550
- json: new Set([
551
- 'dump', 'dumps', 'load', 'loads',
552
- 'JSONDecoder', 'JSONEncoder', 'JSONDecodeError',
553
- 'tool',
554
- ]),
555
- sys: new Set([
556
- 'argv', 'exit', 'path', 'modules', 'stdin', 'stdout', 'stderr',
557
- 'version', 'version_info', 'platform', 'executable', 'prefix',
558
- 'exec_prefix', 'maxsize', 'maxunicode', 'byteorder', 'builtin_module_names',
559
- 'flags', 'float_info', 'hash_info', 'implementation', 'int_info',
560
- 'getdefaultencoding', 'getfilesystemencoding', 'getrecursionlimit',
561
- 'getrefcount', 'getsizeof', 'gettrace', 'getprofile',
562
- 'setrecursionlimit', 'settrace', 'setprofile',
563
- 'exc_info', 'last_type', 'last_value', 'last_traceback',
564
- 'api_version', 'copyright', 'dont_write_bytecode',
565
- 'ps1', 'ps2', 'intern', 'is_finalizing',
566
- 'orig_argv', 'platlibdir', 'stdlib_module_names',
567
- 'thread_info', 'unraisablehook', 'winver',
568
- 'addaudithook', 'audit', 'breakpointhook',
569
- 'call_tracing', 'displayhook', 'excepthook',
570
- 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
571
- 'getallocatedblocks', 'getwindowsversion',
572
- 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth',
573
- 'set_int_max_str_digits', 'get_int_max_str_digits',
574
- 'activate_stack_trampoline', 'deactivate_stack_trampoline',
575
- 'is_stack_trampoline_active', 'last_exc',
576
- 'monitoring', 'exception',
577
- ]),
578
- re: new Set([
579
- 'compile', 'search', 'match', 'fullmatch', 'split', 'findall',
580
- 'finditer', 'sub', 'subn', 'escape', 'purge', 'error',
581
- 'Pattern', 'Match',
582
- 'A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE',
583
- 'L', 'LOCALE', 'M', 'MULTILINE', 'NOFLAG',
584
- 'S', 'U', 'UNICODE', 'VERBOSE', 'X',
585
- ]),
586
- math: new Set([
587
- 'ceil', 'comb', 'copysign', 'fabs', 'factorial', 'floor',
588
- 'fmod', 'frexp', 'fsum', 'gcd', 'isclose', 'isfinite',
589
- 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'log', 'log10',
590
- 'log1p', 'log2', 'modf', 'perm', 'pow', 'prod', 'remainder',
591
- 'trunc', 'ulp', 'nextafter', 'sumprod',
592
- 'exp', 'exp2', 'expm1', 'sqrt', 'cbrt',
593
- 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh',
594
- 'cos', 'cosh', 'degrees', 'dist', 'hypot', 'radians',
595
- 'sin', 'sinh', 'tan', 'tanh',
596
- 'erf', 'erfc', 'gamma', 'lgamma',
597
- 'pi', 'e', 'tau', 'inf', 'nan',
598
- ]),
599
- datetime: new Set([
600
- 'date', 'time', 'datetime', 'timedelta', 'timezone', 'tzinfo',
601
- 'MINYEAR', 'MAXYEAR', 'UTC',
602
- ]),
603
- pathlib: new Set([
604
- 'Path', 'PurePath', 'PurePosixPath', 'PureWindowsPath',
605
- 'PosixPath', 'WindowsPath',
606
- ]),
607
- subprocess: new Set([
608
- 'run', 'call', 'check_call', 'check_output', 'Popen',
609
- 'PIPE', 'STDOUT', 'DEVNULL', 'CompletedProcess',
610
- 'CalledProcessError', 'SubprocessError', 'TimeoutExpired',
611
- 'getoutput', 'getstatusoutput',
612
- ]),
613
- shutil: new Set([
614
- 'copy', 'copy2', 'copyfile', 'copyfileobj', 'copymode', 'copystat',
615
- 'copytree', 'rmtree', 'move', 'disk_usage', 'chown', 'which',
616
- 'make_archive', 'get_archive_formats', 'register_archive_format',
617
- 'unregister_archive_format', 'unpack_archive', 'get_unpack_formats',
618
- 'register_unpack_format', 'unregister_unpack_format',
619
- 'get_terminal_size', 'SameFileError',
620
- ]),
621
- collections: new Set([
622
- 'ChainMap', 'Counter', 'OrderedDict', 'UserDict', 'UserList',
623
- 'UserString', 'abc', 'defaultdict', 'deque', 'namedtuple',
624
- ]),
625
- hashlib: new Set([
626
- 'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
627
- 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
628
- 'blake2b', 'blake2s', 'shake_128', 'shake_256',
629
- 'new', 'algorithms_available', 'algorithms_guaranteed',
630
- 'pbkdf2_hmac', 'scrypt', 'file_digest',
631
- ]),
632
- random: new Set([
633
- 'seed', 'getstate', 'setstate', 'getrandbits',
634
- 'randrange', 'randint', 'choice', 'choices', 'shuffle', 'sample',
635
- 'random', 'uniform', 'triangular', 'betavariate', 'expovariate',
636
- 'gammavariate', 'gauss', 'lognormvariate', 'normalvariate',
637
- 'vonmisesvariate', 'paretovariate', 'weibullvariate',
638
- 'Random', 'SystemRandom', 'randbytes',
639
- ]),
640
- time: new Set([
641
- 'time', 'time_ns', 'clock_gettime', 'clock_gettime_ns',
642
- 'clock_settime', 'clock_settime_ns', 'clock_getres',
643
- 'gmtime', 'localtime', 'mktime', 'asctime', 'ctime',
644
- 'strftime', 'strptime', 'sleep', 'monotonic', 'monotonic_ns',
645
- 'perf_counter', 'perf_counter_ns', 'process_time', 'process_time_ns',
646
- 'thread_time', 'thread_time_ns', 'get_clock_info',
647
- 'struct_time', 'timezone', 'altzone', 'daylight', 'tzname',
648
- 'CLOCK_BOOTTIME', 'CLOCK_MONOTONIC', 'CLOCK_MONOTONIC_RAW',
649
- 'CLOCK_PROCESS_CPUTIME_ID', 'CLOCK_REALTIME',
650
- 'CLOCK_TAI', 'CLOCK_THREAD_CPUTIME_ID',
651
- ]),
652
- csv: new Set([
653
- 'reader', 'writer', 'DictReader', 'DictWriter',
654
- 'Sniffer', 'register_dialect', 'unregister_dialect',
655
- 'get_dialect', 'list_dialects', 'field_size_limit',
656
- 'QUOTE_ALL', 'QUOTE_MINIMAL', 'QUOTE_NONNUMERIC', 'QUOTE_NONE',
657
- 'QUOTE_NOTNULL', 'QUOTE_STRINGS',
658
- 'Dialect', 'Error', 'excel', 'excel_tab', 'unix_dialect',
659
- ]),
660
- logging: new Set([
661
- 'getLogger', 'basicConfig', 'shutdown', 'setLoggerClass',
662
- 'setLogRecordFactory', 'lastResort', 'captureWarnings',
663
- 'debug', 'info', 'warning', 'error', 'critical', 'exception',
664
- 'log', 'disable', 'addLevelName', 'getLevelName', 'getLevelNamesMapping',
665
- 'makeLogRecord', 'getHandlerByName', 'getHandlerNames',
666
- 'Logger', 'Handler', 'Formatter', 'Filter', 'LogRecord',
667
- 'StreamHandler', 'FileHandler', 'NullHandler',
668
- 'BufferingFormatter', 'LoggerAdapter', 'PercentStyle',
669
- 'StrFormatStyle', 'StringTemplateStyle',
670
- 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL',
671
- 'FATAL', 'WARN', 'NOTSET',
672
- 'raiseExceptions', 'root',
673
- 'handlers', 'config',
674
- ]),
675
- };
@@ -247,6 +247,33 @@ func check() {
247
247
  expect(failures).toHaveLength(1);
248
248
  expect(failures[0].details).toContain('Exists');
249
249
  });
250
+ it('should NOT flag real Go stdlib functions (os.ReadFile, fmt.Print, math.Max)', async () => {
251
+ mockFindFiles.mockResolvedValue(['main.go']);
252
+ mockReadFile.mockResolvedValue(`
253
+ package main
254
+
255
+ import (
256
+ "fmt"
257
+ "math"
258
+ "os"
259
+ )
260
+
261
+ func main() {
262
+ data, err := os.ReadFile("config.json")
263
+ if err != nil {
264
+ fmt.Printf("error: %v\n", err)
265
+ return
266
+ }
267
+ fmt.Println(string(data))
268
+ fmt.Print("done\n")
269
+ x := math.Max(1.5, 2.5)
270
+ fmt.Sprintf("max: %f", x)
271
+ fmt.Fprintf(os.Stderr, "log\n")
272
+ }
273
+ `);
274
+ const failures = await gate.run({ cwd: '/project' });
275
+ expect(failures).toHaveLength(0);
276
+ });
250
277
  });
251
278
  describe('PhantomApisGate — C#', () => {
252
279
  let gate;
@@ -317,4 +344,29 @@ class Service {
317
344
  const failures = await gate.run({ cwd: '/project' });
318
345
  expect(failures.length).toBeGreaterThanOrEqual(1);
319
346
  });
347
+ it('should NOT flag real Java methods (Deque.push, StringBuilder.append, stream().sorted(), List.reversed())', async () => {
348
+ mockFindFiles.mockResolvedValue(['RealJava.java']);
349
+ mockReadFile.mockResolvedValue(`
350
+ import java.util.*;
351
+ import java.util.stream.*;
352
+ class RealJava {
353
+ void test() {
354
+ Deque<String> deque = new ArrayDeque<>();
355
+ deque.push("hello");
356
+
357
+ Stack<Integer> stack = new Stack<>();
358
+ stack.push(42);
359
+
360
+ StringBuilder sb = new StringBuilder();
361
+ sb.append("world");
362
+
363
+ List<Integer> nums = List.of(3, 1, 2);
364
+ List<Integer> sorted = nums.stream().sorted().collect(Collectors.toList());
365
+ List<Integer> rev = nums.reversed();
366
+ }
367
+ }
368
+ `);
369
+ const failures = await gate.run({ cwd: '/project' });
370
+ expect(failures).toHaveLength(0);
371
+ });
320
372
  });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Helper utilities for promise-safety gate.
3
+ * Extracted to keep promise-safety.ts under 500 lines.
4
+ */
5
+ export interface PromiseViolation {
6
+ file: string;
7
+ line: number;
8
+ type: 'unhandled-then' | 'unsafe-parse' | 'async-no-await' | 'unsafe-fetch' | 'ignored-error' | 'deadlock-risk' | 'bare-except';
9
+ code: string;
10
+ reason: string;
11
+ }
12
+ export declare function extractBraceBody(content: string, startIdx: number): string | null;
13
+ export declare function extractIndentedBody(content: string, startIdx: number): string | null;
14
+ export declare function isInsideTryBlock(lines: string[], lineIdx: number): boolean;
15
+ export declare function isInsidePythonTry(lines: string[], lineIdx: number): boolean;
16
+ export declare function isInsideRubyRescue(lines: string[], lineIdx: number): boolean;
17
+ export declare function hasCatchAhead(lines: string[], idx: number): boolean;
18
+ export declare function hasStatusCheckAhead(lines: string[], idx: number): boolean;
19
+ export declare function stripStrings(line: string): string;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Helper utilities for promise-safety gate.
3
+ * Extracted to keep promise-safety.ts under 500 lines.
4
+ */
5
+ export function extractBraceBody(content, startIdx) {
6
+ let depth = 1;
7
+ let idx = startIdx;
8
+ while (depth > 0 && idx < content.length) {
9
+ if (content[idx] === '{')
10
+ depth++;
11
+ if (content[idx] === '}')
12
+ depth--;
13
+ idx++;
14
+ }
15
+ return depth === 0 ? content.substring(startIdx, idx - 1) : null;
16
+ }
17
+ export function extractIndentedBody(content, startIdx) {
18
+ const rest = content.substring(startIdx);
19
+ const lines = rest.split('\n');
20
+ if (lines.length < 2)
21
+ return null;
22
+ let bodyIndent = -1;
23
+ const bodyLines = [];
24
+ for (let i = 1; i < lines.length; i++) {
25
+ const line = lines[i];
26
+ if (line.trim() === '' || line.trim().startsWith('#')) {
27
+ bodyLines.push(line);
28
+ continue;
29
+ }
30
+ const indent = line.length - line.trimStart().length;
31
+ if (bodyIndent === -1) {
32
+ bodyIndent = indent;
33
+ }
34
+ if (indent < bodyIndent)
35
+ break;
36
+ bodyLines.push(line);
37
+ }
38
+ return bodyLines.join('\n');
39
+ }
40
+ export function isInsideTryBlock(lines, lineIdx) {
41
+ let braceDepth = 0;
42
+ for (let j = lineIdx - 1; j >= Math.max(0, lineIdx - 30); j--) {
43
+ const prevLine = stripStrings(lines[j]);
44
+ for (const ch of prevLine) {
45
+ if (ch === '}')
46
+ braceDepth++;
47
+ if (ch === '{')
48
+ braceDepth--;
49
+ }
50
+ if (/\btry\s*\{/.test(prevLine) && braceDepth <= 0)
51
+ return true;
52
+ if (/\}\s*catch\s*\(/.test(prevLine))
53
+ return false;
54
+ }
55
+ return false;
56
+ }
57
+ export function isInsidePythonTry(lines, lineIdx) {
58
+ const lineIndent = lines[lineIdx].length - lines[lineIdx].trimStart().length;
59
+ for (let j = lineIdx - 1; j >= Math.max(0, lineIdx - 30); j--) {
60
+ const trimmed = lines[j].trim();
61
+ if (trimmed === '')
62
+ continue;
63
+ const indent = lines[j].length - lines[j].trimStart().length;
64
+ if (indent < lineIndent && /^\s*try\s*:/.test(lines[j]))
65
+ return true;
66
+ if (indent < lineIndent && /^\s*(?:except|finally)\s*/.test(lines[j]))
67
+ return false;
68
+ if (indent === 0 && /^(?:def|class|async\s+def)\s/.test(trimmed))
69
+ break;
70
+ }
71
+ return false;
72
+ }
73
+ export function isInsideRubyRescue(lines, lineIdx) {
74
+ for (let j = lineIdx - 1; j >= Math.max(0, lineIdx - 30); j--) {
75
+ const trimmed = lines[j].trim();
76
+ if (trimmed === 'begin')
77
+ return true;
78
+ if (/^rescue\b/.test(trimmed))
79
+ return false;
80
+ if (/^(?:def|class|module)\s/.test(trimmed))
81
+ break;
82
+ }
83
+ return false;
84
+ }
85
+ export function hasCatchAhead(lines, idx) {
86
+ for (let j = idx; j < Math.min(idx + 10, lines.length); j++) {
87
+ if (/\.catch\s*\(/.test(lines[j]))
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+ export function hasStatusCheckAhead(lines, idx) {
93
+ for (let j = idx; j < Math.min(idx + 10, lines.length); j++) {
94
+ if (/\.\s*ok\b/.test(lines[j]) || /\.status(?:Text)?\b/.test(lines[j]))
95
+ return true;
96
+ }
97
+ return false;
98
+ }
99
+ export function stripStrings(line) {
100
+ return line.replace(/`[^`]*`/g, '""').replace(/"[^"]*"/g, '""').replace(/'[^']*'/g, '""');
101
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Language detection data for promise-safety gate.
3
+ * Extracted to keep promise-safety.ts under 500 lines.
4
+ */
5
+ export type Lang = 'js' | 'python' | 'go' | 'ruby' | 'csharp' | 'unknown';
6
+ export declare const LANG_EXTENSIONS: Record<string, Lang>;
7
+ export declare const LANG_GLOBS: Record<Lang, string[]>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Language detection data for promise-safety gate.
3
+ * Extracted to keep promise-safety.ts under 500 lines.
4
+ */
5
+ export const LANG_EXTENSIONS = {
6
+ '.ts': 'js', '.tsx': 'js', '.js': 'js', '.jsx': 'js', '.mjs': 'js', '.cjs': 'js',
7
+ '.py': 'python', '.pyw': 'python',
8
+ '.go': 'go',
9
+ '.rb': 'ruby', '.rake': 'ruby',
10
+ '.cs': 'csharp',
11
+ };
12
+ export const LANG_GLOBS = {
13
+ js: ['**/*.{ts,js,tsx,jsx,mjs,cjs}'],
14
+ python: ['**/*.py'],
15
+ go: ['**/*.go'],
16
+ ruby: ['**/*.rb'],
17
+ csharp: ['**/*.cs'],
18
+ unknown: [],
19
+ };