@rigour-labs/core 3.0.3 → 3.0.5

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.
@@ -0,0 +1,724 @@
1
+ /**
2
+ * Deprecated APIs Gate
3
+ *
4
+ * Detects usage of deprecated, removed, or insecure stdlib/framework APIs.
5
+ * AI models are trained on historical code and frequently suggest deprecated patterns
6
+ * that introduce security vulnerabilities, performance issues, or will break on upgrade.
7
+ *
8
+ * Categories:
9
+ * 1. Security-deprecated: APIs removed for security reasons (e.g. new Buffer(), md5 for passwords)
10
+ * 2. Removed APIs: Methods that no longer exist in current versions
11
+ * 3. Superseded APIs: Working but replaced by better alternatives
12
+ *
13
+ * Supported languages:
14
+ * JS/TS — Node.js 22.x deprecations, Web API deprecations
15
+ * Python — Python 3.12+ deprecations and removals
16
+ * Go — Deprecated stdlib patterns (ioutil, etc.)
17
+ * C# — Deprecated .NET APIs (WebClient, BinaryFormatter, etc.)
18
+ * Java — Deprecated JDK APIs (Date, Vector, Hashtable, etc.)
19
+ *
20
+ * @since v3.0.0
21
+ * @since v3.0.3 — Go, C#, Java deprecated API detection added
22
+ */
23
+ import { Gate } from './base.js';
24
+ import { FileScanner } from '../utils/scanner.js';
25
+ import { Logger } from '../utils/logger.js';
26
+ import fs from 'fs-extra';
27
+ import path from 'path';
28
+ export class DeprecatedApisGate extends Gate {
29
+ config;
30
+ constructor(config = {}) {
31
+ super('deprecated-apis', 'Deprecated API Detection');
32
+ this.config = {
33
+ enabled: config.enabled ?? true,
34
+ check_node: config.check_node ?? true,
35
+ check_python: config.check_python ?? true,
36
+ check_web: config.check_web ?? true,
37
+ check_go: config.check_go ?? true,
38
+ check_csharp: config.check_csharp ?? true,
39
+ check_java: config.check_java ?? true,
40
+ block_security_deprecated: config.block_security_deprecated ?? true,
41
+ ignore_patterns: config.ignore_patterns ?? [],
42
+ };
43
+ }
44
+ get provenance() { return 'ai-drift'; }
45
+ async run(context) {
46
+ if (!this.config.enabled)
47
+ return [];
48
+ const failures = [];
49
+ const deprecated = [];
50
+ const files = await FileScanner.findFiles({
51
+ cwd: context.cwd,
52
+ patterns: ['**/*.{ts,js,tsx,jsx,py,go,cs,java,kt}'],
53
+ ignore: [...(context.ignore || []), '**/node_modules/**', '**/dist/**', '**/build/**',
54
+ '**/.venv/**', '**/venv/**', '**/vendor/**', '**/__pycache__/**',
55
+ '**/bin/Debug/**', '**/bin/Release/**', '**/obj/**',
56
+ '**/target/**', '**/.gradle/**', '**/out/**'],
57
+ });
58
+ Logger.info(`Deprecated APIs: Scanning ${files.length} files`);
59
+ for (const file of files) {
60
+ try {
61
+ const fullPath = path.join(context.cwd, file);
62
+ const content = await fs.readFile(fullPath, 'utf-8');
63
+ const ext = path.extname(file);
64
+ if (['.ts', '.js', '.tsx', '.jsx'].includes(ext)) {
65
+ if (this.config.check_node)
66
+ this.checkNodeDeprecated(content, file, deprecated);
67
+ if (this.config.check_web)
68
+ this.checkWebDeprecated(content, file, deprecated);
69
+ }
70
+ else if (ext === '.py' && this.config.check_python) {
71
+ this.checkPythonDeprecated(content, file, deprecated);
72
+ }
73
+ else if (ext === '.go' && this.config.check_go) {
74
+ this.checkGoDeprecated(content, file, deprecated);
75
+ }
76
+ else if (ext === '.cs' && this.config.check_csharp) {
77
+ this.checkCSharpDeprecated(content, file, deprecated);
78
+ }
79
+ else if ((ext === '.java' || ext === '.kt') && this.config.check_java) {
80
+ this.checkJavaDeprecated(content, file, deprecated);
81
+ }
82
+ }
83
+ catch { /* skip */ }
84
+ }
85
+ // Group by file and severity
86
+ const byFile = new Map();
87
+ for (const d of deprecated) {
88
+ const existing = byFile.get(d.file) || [];
89
+ existing.push(d);
90
+ byFile.set(d.file, existing);
91
+ }
92
+ for (const [file, usages] of byFile) {
93
+ // Separate security-deprecated (critical) from others (medium)
94
+ const securityUsages = usages.filter(u => u.category === 'security');
95
+ const otherUsages = usages.filter(u => u.category !== 'security');
96
+ if (securityUsages.length > 0) {
97
+ const details = securityUsages.map(u => ` L${u.line}: ${u.api} — ${u.reason} → Use ${u.replacement}`).join('\n');
98
+ failures.push(this.createFailure(`Security-deprecated APIs in ${file}:\n${details}`, [file], `These APIs were deprecated for security reasons. Using them introduces known vulnerabilities. Replace with the suggested alternatives immediately.`, 'Security-Deprecated APIs', securityUsages[0].line, undefined, this.config.block_security_deprecated ? 'critical' : 'high'));
99
+ }
100
+ if (otherUsages.length > 0) {
101
+ const details = otherUsages.map(u => ` L${u.line}: ${u.api} — ${u.reason} → Use ${u.replacement}`).join('\n');
102
+ failures.push(this.createFailure(`Deprecated APIs in ${file}:\n${details}`, [file], `These APIs are deprecated or removed. AI models trained on older code frequently suggest them. Update to current alternatives.`, 'Deprecated APIs', otherUsages[0].line, undefined, 'medium'));
103
+ }
104
+ }
105
+ return failures;
106
+ }
107
+ checkNodeDeprecated(content, file, deprecated) {
108
+ const lines = content.split('\n');
109
+ for (let i = 0; i < lines.length; i++) {
110
+ const line = lines[i];
111
+ const trimmed = line.trim();
112
+ // Skip comments
113
+ if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*'))
114
+ continue;
115
+ for (const rule of NODE_DEPRECATED_RULES) {
116
+ if (rule.pattern.test(line)) {
117
+ deprecated.push({
118
+ file, line: i + 1,
119
+ api: rule.api,
120
+ reason: rule.reason,
121
+ replacement: rule.replacement,
122
+ category: rule.category,
123
+ });
124
+ }
125
+ }
126
+ }
127
+ }
128
+ checkWebDeprecated(content, file, deprecated) {
129
+ const lines = content.split('\n');
130
+ for (let i = 0; i < lines.length; i++) {
131
+ const line = lines[i];
132
+ const trimmed = line.trim();
133
+ if (trimmed.startsWith('//') || trimmed.startsWith('*'))
134
+ continue;
135
+ for (const rule of WEB_DEPRECATED_RULES) {
136
+ if (rule.pattern.test(line)) {
137
+ deprecated.push({
138
+ file, line: i + 1,
139
+ api: rule.api,
140
+ reason: rule.reason,
141
+ replacement: rule.replacement,
142
+ category: rule.category,
143
+ });
144
+ }
145
+ }
146
+ }
147
+ }
148
+ checkPythonDeprecated(content, file, deprecated) {
149
+ const lines = content.split('\n');
150
+ for (let i = 0; i < lines.length; i++) {
151
+ const line = lines[i];
152
+ const trimmed = line.trim();
153
+ if (trimmed.startsWith('#'))
154
+ continue;
155
+ for (const rule of PYTHON_DEPRECATED_RULES) {
156
+ if (rule.pattern.test(line)) {
157
+ deprecated.push({
158
+ file, line: i + 1,
159
+ api: rule.api,
160
+ reason: rule.reason,
161
+ replacement: rule.replacement,
162
+ category: rule.category,
163
+ });
164
+ }
165
+ }
166
+ }
167
+ }
168
+ checkGoDeprecated(content, file, deprecated) {
169
+ const lines = content.split('\n');
170
+ for (let i = 0; i < lines.length; i++) {
171
+ const line = lines[i];
172
+ const trimmed = line.trim();
173
+ if (trimmed.startsWith('//'))
174
+ continue;
175
+ for (const rule of GO_DEPRECATED_RULES) {
176
+ if (rule.pattern.test(line)) {
177
+ deprecated.push({
178
+ file, line: i + 1,
179
+ api: rule.api, reason: rule.reason,
180
+ replacement: rule.replacement, category: rule.category,
181
+ });
182
+ }
183
+ }
184
+ }
185
+ }
186
+ checkCSharpDeprecated(content, file, deprecated) {
187
+ const lines = content.split('\n');
188
+ for (let i = 0; i < lines.length; i++) {
189
+ const line = lines[i];
190
+ const trimmed = line.trim();
191
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*'))
192
+ continue;
193
+ for (const rule of CSHARP_DEPRECATED_RULES) {
194
+ if (rule.pattern.test(line)) {
195
+ deprecated.push({
196
+ file, line: i + 1,
197
+ api: rule.api, reason: rule.reason,
198
+ replacement: rule.replacement, category: rule.category,
199
+ });
200
+ }
201
+ }
202
+ }
203
+ }
204
+ checkJavaDeprecated(content, file, deprecated) {
205
+ const lines = content.split('\n');
206
+ for (let i = 0; i < lines.length; i++) {
207
+ const line = lines[i];
208
+ const trimmed = line.trim();
209
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*'))
210
+ continue;
211
+ for (const rule of JAVA_DEPRECATED_RULES) {
212
+ if (rule.pattern.test(line)) {
213
+ deprecated.push({
214
+ file, line: i + 1,
215
+ api: rule.api, reason: rule.reason,
216
+ replacement: rule.replacement, category: rule.category,
217
+ });
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+ /**
224
+ * Node.js deprecated APIs — sourced from official Node.js deprecation list
225
+ */
226
+ const NODE_DEPRECATED_RULES = [
227
+ // Security-deprecated
228
+ {
229
+ pattern: /new\s+Buffer\s*\(/,
230
+ api: 'new Buffer()',
231
+ reason: 'DEP0005: Security vulnerability — uninitialized memory exposure',
232
+ replacement: 'Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe()',
233
+ category: 'security',
234
+ },
235
+ {
236
+ pattern: /Buffer\s*\(\s*(?:\d|['"])/,
237
+ api: 'Buffer() constructor',
238
+ reason: 'DEP0005: Security vulnerability — uninitialized memory exposure',
239
+ replacement: 'Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe()',
240
+ category: 'security',
241
+ },
242
+ {
243
+ pattern: /createCipher\s*\(/,
244
+ api: 'crypto.createCipher()',
245
+ reason: 'DEP0106: Uses weak key derivation (no IV, no salt)',
246
+ replacement: 'crypto.createCipheriv() with explicit IV',
247
+ category: 'security',
248
+ },
249
+ {
250
+ pattern: /createDecipher\s*\(/,
251
+ api: 'crypto.createDecipher()',
252
+ reason: 'DEP0106: Uses weak key derivation (no IV, no salt)',
253
+ replacement: 'crypto.createDecipheriv() with explicit IV',
254
+ category: 'security',
255
+ },
256
+ // Removed
257
+ {
258
+ pattern: /\brequire\s*\(\s*['"]domain['"]\s*\)/,
259
+ api: "require('domain')",
260
+ reason: 'DEP0032: domain module is deprecated (error handling issues)',
261
+ replacement: 'async_hooks, try/catch, or Promise error handling',
262
+ category: 'removed',
263
+ },
264
+ {
265
+ pattern: /\brequire\s*\(\s*['"]punycode['"]\s*\)/,
266
+ api: "require('punycode')",
267
+ reason: 'DEP0040: punycode module removed from Node.js core',
268
+ replacement: 'npm package: punycode (userland)',
269
+ category: 'removed',
270
+ },
271
+ {
272
+ pattern: /\brequire\s*\(\s*['"]sys['"]\s*\)/,
273
+ api: "require('sys')",
274
+ reason: 'DEP0025: sys module was renamed to util',
275
+ replacement: "require('util')",
276
+ category: 'removed',
277
+ },
278
+ {
279
+ pattern: /\brequire\s*\(\s*['"]_linklist['"]\s*\)/,
280
+ api: "require('_linklist')",
281
+ reason: 'DEP0037: _linklist module removed',
282
+ replacement: 'npm userland linked list package',
283
+ category: 'removed',
284
+ },
285
+ // Superseded
286
+ {
287
+ pattern: /url\.parse\s*\(/,
288
+ api: 'url.parse()',
289
+ reason: 'DEP0169: Legacy URL parser has known vulnerabilities',
290
+ replacement: 'new URL() (WHATWG URL API)',
291
+ category: 'superseded',
292
+ },
293
+ {
294
+ pattern: /url\.resolve\s*\(/,
295
+ api: 'url.resolve()',
296
+ reason: 'DEP0169: Legacy URL API',
297
+ replacement: 'new URL(relative, base)',
298
+ category: 'superseded',
299
+ },
300
+ {
301
+ pattern: /url\.format\s*\(\s*(?:url\.parse|{)/,
302
+ api: 'url.format(urlObject)',
303
+ reason: 'DEP0169: Legacy URL API with url.parse objects',
304
+ replacement: 'new URL().toString() or url.format(new URL(...))',
305
+ category: 'superseded',
306
+ },
307
+ {
308
+ pattern: /\.send\s*\(\s*new\s+Buffer\b/,
309
+ api: 'Sending raw Buffer',
310
+ reason: 'Potential uninitialized memory leak when Buffer() used without alloc',
311
+ replacement: 'Buffer.from() or Buffer.alloc()',
312
+ category: 'security',
313
+ },
314
+ {
315
+ pattern: /fs\.exists\s*\(/,
316
+ api: 'fs.exists()',
317
+ reason: 'DEP0103: fs.exists() is deprecated (race condition issues)',
318
+ replacement: 'fs.access() or fs.stat()',
319
+ category: 'superseded',
320
+ },
321
+ {
322
+ pattern: /util\.inherits\s*\(/,
323
+ api: 'util.inherits()',
324
+ reason: 'DEP0: Superseded by ES6 class extends',
325
+ replacement: 'class Child extends Parent {}',
326
+ category: 'superseded',
327
+ },
328
+ {
329
+ pattern: /util\.pump\s*\(/,
330
+ api: 'util.pump()',
331
+ reason: 'DEP0004: Removed — use stream.pipeline()',
332
+ replacement: 'stream.pipeline() or pipe()',
333
+ category: 'removed',
334
+ },
335
+ {
336
+ pattern: /util\.puts\s*\(|util\.print\s*\(|util\.debug\s*\(/,
337
+ api: 'util.puts/print/debug()',
338
+ reason: 'DEP0027/28/29: Removed console wrappers',
339
+ replacement: 'console.log() / console.error()',
340
+ category: 'removed',
341
+ },
342
+ {
343
+ pattern: /SlowBuffer\s*\(/,
344
+ api: 'SlowBuffer',
345
+ reason: 'DEP0030: Deprecated class',
346
+ replacement: 'Buffer.allocUnsafeSlow()',
347
+ category: 'superseded',
348
+ },
349
+ {
350
+ pattern: /\.setEncoding\s*\(\s*['"]binary['"]\s*\)/,
351
+ api: "setEncoding('binary')",
352
+ reason: "DEP0040: 'binary' encoding is deprecated",
353
+ replacement: "'latin1' encoding",
354
+ category: 'superseded',
355
+ },
356
+ {
357
+ pattern: /process\.(?:assert|binding)\s*\(/,
358
+ api: 'process.assert()/binding()',
359
+ reason: 'DEP0064/0098: Internal APIs removed',
360
+ replacement: 'assert module / public APIs',
361
+ category: 'removed',
362
+ },
363
+ ];
364
+ /**
365
+ * Web API deprecated patterns
366
+ */
367
+ const WEB_DEPRECATED_RULES = [
368
+ {
369
+ pattern: /document\.write\s*\(/,
370
+ api: 'document.write()',
371
+ reason: 'Blocks parsing, security risk (XSS vector), removed in strict mode',
372
+ replacement: 'DOM manipulation (createElement, appendChild, innerHTML)',
373
+ category: 'security',
374
+ },
375
+ {
376
+ pattern: /\.innerHTML\s*=\s*[`'"]/,
377
+ api: 'innerHTML assignment with strings',
378
+ reason: 'XSS vulnerability when used with user-supplied content',
379
+ replacement: 'textContent, createElement + appendChild, or DOMPurify.sanitize()',
380
+ category: 'security',
381
+ },
382
+ {
383
+ pattern: /eval\s*\(\s*[^)]/,
384
+ api: 'eval()',
385
+ reason: 'Code injection vulnerability, prevents optimization',
386
+ replacement: 'JSON.parse(), Function constructor (if absolutely needed), or structured approach',
387
+ category: 'security',
388
+ },
389
+ {
390
+ pattern: /with\s*\(\s*\w/,
391
+ api: 'with statement',
392
+ reason: 'Removed in strict mode, creates ambiguous scope, security risk',
393
+ replacement: 'Destructuring or explicit property access',
394
+ category: 'removed',
395
+ },
396
+ {
397
+ pattern: /document\.all\b/,
398
+ api: 'document.all',
399
+ reason: 'Legacy IE API, falsy object (quirks mode artifact)',
400
+ replacement: 'document.getElementById(), document.querySelector()',
401
+ category: 'superseded',
402
+ },
403
+ {
404
+ pattern: /escape\s*\(\s*['"]/,
405
+ api: 'escape()',
406
+ reason: 'Deprecated — does not handle Unicode correctly',
407
+ replacement: 'encodeURIComponent() or encodeURI()',
408
+ category: 'superseded',
409
+ },
410
+ {
411
+ pattern: /unescape\s*\(/,
412
+ api: 'unescape()',
413
+ reason: 'Deprecated — does not handle Unicode correctly',
414
+ replacement: 'decodeURIComponent() or decodeURI()',
415
+ category: 'superseded',
416
+ },
417
+ ];
418
+ /**
419
+ * Python deprecated APIs — sourced from Python 3.12+ deprecation notices
420
+ */
421
+ const PYTHON_DEPRECATED_RULES = [
422
+ // Security-deprecated
423
+ {
424
+ pattern: /\bmd5\s*\(|\.md5\s*\(/,
425
+ api: 'hashlib.md5() for passwords',
426
+ reason: 'MD5 is cryptographically broken — collision attacks proven since 2004',
427
+ replacement: 'hashlib.sha256(), hashlib.blake2b(), or bcrypt/argon2 for passwords',
428
+ category: 'security',
429
+ },
430
+ {
431
+ pattern: /\bsha1\s*\(|\.sha1\s*\(/,
432
+ api: 'hashlib.sha1() for security',
433
+ reason: 'SHA-1 is cryptographically broken — SHAttered attack (2017)',
434
+ replacement: 'hashlib.sha256() or hashlib.sha3_256()',
435
+ category: 'security',
436
+ },
437
+ {
438
+ pattern: /\bpickle\.loads?\s*\(/,
439
+ api: 'pickle.load()/loads()',
440
+ reason: 'Arbitrary code execution vulnerability when loading untrusted data',
441
+ replacement: 'json.loads() for data, or use restricted_loads with allowlists',
442
+ category: 'security',
443
+ },
444
+ {
445
+ pattern: /\byaml\.load\s*\([^)]*(?!\bLoader\b)[^)]*\)/,
446
+ api: 'yaml.load() without Loader',
447
+ reason: 'Arbitrary code execution when loading untrusted YAML',
448
+ replacement: 'yaml.safe_load() or yaml.load(data, Loader=yaml.SafeLoader)',
449
+ category: 'security',
450
+ },
451
+ {
452
+ pattern: /\bexec\s*\(\s*(?:input|request|f['"])/,
453
+ api: 'exec() with user input',
454
+ reason: 'Code injection vulnerability',
455
+ replacement: 'ast.literal_eval() for data, structured parsing for expressions',
456
+ category: 'security',
457
+ },
458
+ {
459
+ pattern: /\bos\.system\s*\(/,
460
+ api: 'os.system()',
461
+ reason: 'Shell injection vulnerability, no output capture',
462
+ replacement: 'subprocess.run() with shell=False',
463
+ category: 'security',
464
+ },
465
+ {
466
+ pattern: /subprocess\.(?:call|run|Popen)\s*\([^)]*shell\s*=\s*True/,
467
+ api: 'subprocess with shell=True',
468
+ reason: 'Shell injection vulnerability when args contain user input',
469
+ replacement: 'subprocess.run() with shell=False and list args',
470
+ category: 'security',
471
+ },
472
+ // Removed modules (Python 3.12+)
473
+ {
474
+ pattern: /\bimport\s+imp\b/,
475
+ api: 'import imp',
476
+ reason: 'Removed in Python 3.12 (PEP 594)',
477
+ replacement: 'importlib',
478
+ category: 'removed',
479
+ },
480
+ {
481
+ pattern: /\bimport\s+(?:aifc|audioop|cgi|cgitb|chunk|crypt|imghdr|mailcap|msilib|nis|nntplib|ossaudiodev|pipes|sndhdr|spwd|sunau|telnetlib|uu|xdrlib)\b/,
482
+ api: 'Dead batteries module',
483
+ reason: 'Removed in Python 3.13 (PEP 594 — dead batteries)',
484
+ replacement: 'PyPI equivalents (see PEP 594 for specific replacements)',
485
+ category: 'removed',
486
+ },
487
+ {
488
+ pattern: /\bfrom\s+distutils\b/,
489
+ api: 'distutils',
490
+ reason: 'Removed in Python 3.12 (PEP 632)',
491
+ replacement: 'setuptools or build',
492
+ category: 'removed',
493
+ },
494
+ {
495
+ pattern: /\bimport\s+formatter\b/,
496
+ api: 'import formatter',
497
+ reason: 'Removed in Python 3.10',
498
+ replacement: 'No direct replacement — use string formatting',
499
+ category: 'removed',
500
+ },
501
+ // Superseded
502
+ {
503
+ pattern: /\bfrom\s+collections\s+import\s+(?:Mapping|MutableMapping|Sequence|MutableSequence|Set|MutableSet|Callable|Iterable|Iterator|Generator|Coroutine|Awaitable|AsyncIterable|AsyncIterator|AsyncGenerator|Hashable|Sized|Container|Collection|Reversible|MappingView|KeysView|ItemsView|ValuesView|ByteString)\b/,
504
+ api: 'collections ABCs',
505
+ reason: 'Removed in Python 3.10 — moved to collections.abc',
506
+ replacement: 'from collections.abc import ...',
507
+ category: 'removed',
508
+ },
509
+ {
510
+ pattern: /\boptparse\b/,
511
+ api: 'optparse',
512
+ reason: 'Superseded since Python 3.2',
513
+ replacement: 'argparse',
514
+ category: 'superseded',
515
+ },
516
+ {
517
+ pattern: /\bfrom\s+typing\s+import\s+(?:Dict|List|Set|Tuple|FrozenSet|Type|Deque|DefaultDict|OrderedDict|Counter|ChainMap|Awaitable|Coroutine|AsyncIterable|AsyncIterator|AsyncGenerator|Iterable|Iterator|Generator|Reversible|Container|Collection|Callable|AbstractSet|MutableSet|Mapping|MutableMapping|Sequence|MutableSequence|ByteString|MappingView|KeysView|ItemsView|ValuesView|ContextManager|AsyncContextManager|Pattern|Match)\b/,
518
+ api: 'typing generics (Dict, List, etc.)',
519
+ reason: 'Deprecated since Python 3.9 — use built-in generics (PEP 585)',
520
+ replacement: 'dict[], list[], set[], tuple[] (lowercase built-in types)',
521
+ category: 'superseded',
522
+ },
523
+ {
524
+ pattern: /\bfrom\s+typing\s+import\s+(?:Optional|Union)\b/,
525
+ api: 'typing.Optional / typing.Union',
526
+ reason: 'Superseded in Python 3.10 — use X | Y syntax (PEP 604)',
527
+ replacement: 'X | None instead of Optional[X], X | Y instead of Union[X, Y]',
528
+ category: 'superseded',
529
+ },
530
+ {
531
+ pattern: /\basyncio\.get_event_loop\s*\(\s*\)/,
532
+ api: 'asyncio.get_event_loop()',
533
+ reason: 'Deprecated in Python 3.10 — may create new loop unexpectedly',
534
+ replacement: 'asyncio.get_running_loop() or asyncio.run()',
535
+ category: 'superseded',
536
+ },
537
+ {
538
+ pattern: /\bsetup\s*\(\s*[^)]*\buse_2to3\s*=/,
539
+ api: 'setup(use_2to3=True)',
540
+ reason: 'Removed in setuptools 58+ — Python 2 support dropped',
541
+ replacement: 'Write Python 3 only code',
542
+ category: 'removed',
543
+ },
544
+ ];
545
+ /**
546
+ * Go deprecated APIs — sourced from Go official deprecation notices
547
+ */
548
+ const GO_DEPRECATED_RULES = [
549
+ {
550
+ pattern: /\bioutil\.ReadFile\s*\(/,
551
+ api: 'ioutil.ReadFile()', reason: 'Deprecated since Go 1.16 — io/ioutil package deprecated',
552
+ replacement: 'os.ReadFile()', category: 'superseded',
553
+ },
554
+ {
555
+ pattern: /\bioutil\.WriteFile\s*\(/,
556
+ api: 'ioutil.WriteFile()', reason: 'Deprecated since Go 1.16',
557
+ replacement: 'os.WriteFile()', category: 'superseded',
558
+ },
559
+ {
560
+ pattern: /\bioutil\.ReadAll\s*\(/,
561
+ api: 'ioutil.ReadAll()', reason: 'Deprecated since Go 1.16',
562
+ replacement: 'io.ReadAll()', category: 'superseded',
563
+ },
564
+ {
565
+ pattern: /\bioutil\.ReadDir\s*\(/,
566
+ api: 'ioutil.ReadDir()', reason: 'Deprecated since Go 1.16',
567
+ replacement: 'os.ReadDir()', category: 'superseded',
568
+ },
569
+ {
570
+ pattern: /\bioutil\.TempDir\s*\(/,
571
+ api: 'ioutil.TempDir()', reason: 'Deprecated since Go 1.17',
572
+ replacement: 'os.MkdirTemp()', category: 'superseded',
573
+ },
574
+ {
575
+ pattern: /\bioutil\.TempFile\s*\(/,
576
+ api: 'ioutil.TempFile()', reason: 'Deprecated since Go 1.17',
577
+ replacement: 'os.CreateTemp()', category: 'superseded',
578
+ },
579
+ {
580
+ pattern: /\bioutil\.NopCloser\s*\(/,
581
+ api: 'ioutil.NopCloser()', reason: 'Deprecated since Go 1.16',
582
+ replacement: 'io.NopCloser()', category: 'superseded',
583
+ },
584
+ {
585
+ pattern: /\b"io\/ioutil"/,
586
+ api: 'import "io/ioutil"', reason: 'Entire io/ioutil package deprecated since Go 1.16',
587
+ replacement: 'Use os and io packages instead', category: 'superseded',
588
+ },
589
+ {
590
+ pattern: /\bsort\.IntSlice\b|sort\.Float64Slice\b|sort\.StringSlice\b/,
591
+ api: 'sort.*Slice types', reason: 'Superseded since Go 1.21',
592
+ replacement: 'slices.Sort() or sort.Slice()', category: 'superseded',
593
+ },
594
+ {
595
+ pattern: /\bmath\/rand"[\s\S]*?rand\.(Seed|Read)\s*\(/,
596
+ api: 'rand.Seed() / rand.Read()', reason: 'Deprecated in Go 1.20+',
597
+ replacement: 'Auto-seeded in Go 1.20+; use crypto/rand.Read()', category: 'superseded',
598
+ },
599
+ {
600
+ pattern: /\bstrings\.Title\s*\(/,
601
+ api: 'strings.Title()', reason: 'Deprecated since Go 1.18 — broken for Unicode',
602
+ replacement: 'golang.org/x/text/cases.Title()', category: 'superseded',
603
+ },
604
+ ];
605
+ /**
606
+ * C# deprecated APIs — sourced from .NET deprecation notices
607
+ */
608
+ const CSHARP_DEPRECATED_RULES = [
609
+ {
610
+ pattern: /\bnew\s+WebClient\s*\(/,
611
+ api: 'WebClient', reason: 'Deprecated in .NET 6+ — poor async support',
612
+ replacement: 'HttpClient', category: 'superseded',
613
+ },
614
+ {
615
+ pattern: /\bBinaryFormatter\b/,
616
+ api: 'BinaryFormatter', reason: 'Security vulnerability — arbitrary code execution on deserialization',
617
+ replacement: 'System.Text.Json or JsonSerializer', category: 'security',
618
+ },
619
+ {
620
+ pattern: /\bJavaScriptSerializer\b/,
621
+ api: 'JavaScriptSerializer', reason: 'Deprecated — poor performance and limited features',
622
+ replacement: 'System.Text.Json.JsonSerializer', category: 'superseded',
623
+ },
624
+ {
625
+ pattern: /\bThread\.Abort\s*\(/,
626
+ api: 'Thread.Abort()', reason: 'Throws PlatformNotSupportedException in .NET 5+',
627
+ replacement: 'CancellationToken for cooperative cancellation', category: 'removed',
628
+ },
629
+ {
630
+ pattern: /\bThread\.Suspend\s*\(|Thread\.Resume\s*\(/,
631
+ api: 'Thread.Suspend/Resume()', reason: 'Deprecated — causes deadlocks',
632
+ replacement: 'ManualResetEvent or SemaphoreSlim', category: 'removed',
633
+ },
634
+ {
635
+ pattern: /\bAppDomain\.CreateDomain\s*\(/,
636
+ api: 'AppDomain.CreateDomain()', reason: 'Not supported in .NET Core/5+',
637
+ replacement: 'AssemblyLoadContext', category: 'removed',
638
+ },
639
+ {
640
+ pattern: /\bRemoting\b.*\bChannel\b/,
641
+ api: '.NET Remoting', reason: 'Removed in .NET Core/5+',
642
+ replacement: 'gRPC, REST APIs, or SignalR', category: 'removed',
643
+ },
644
+ {
645
+ pattern: /\bnew\s+SHA1(?:Managed|CryptoServiceProvider)\s*\(/,
646
+ api: 'SHA1Managed/CryptoServiceProvider', reason: 'SHA-1 cryptographically broken',
647
+ replacement: 'SHA256.Create() or SHA512.Create()', category: 'security',
648
+ },
649
+ {
650
+ pattern: /\bnew\s+MD5CryptoServiceProvider\s*\(/,
651
+ api: 'MD5CryptoServiceProvider', reason: 'MD5 cryptographically broken',
652
+ replacement: 'SHA256.Create() or SHA512.Create()', category: 'security',
653
+ },
654
+ {
655
+ pattern: /\bnew\s+(?:RijndaelManaged|DESCryptoServiceProvider|RC2CryptoServiceProvider|TripleDESCryptoServiceProvider)\s*\(/,
656
+ api: 'Legacy crypto providers', reason: 'Weak encryption algorithms',
657
+ replacement: 'Aes.Create()', category: 'security',
658
+ },
659
+ ];
660
+ /**
661
+ * Java deprecated APIs — sourced from JDK deprecation notices
662
+ */
663
+ const JAVA_DEPRECATED_RULES = [
664
+ {
665
+ pattern: /\bnew\s+Date\s*\(\s*\d/,
666
+ api: 'new Date(year, month, ...)', reason: 'Deprecated since JDK 1.1',
667
+ replacement: 'java.time.LocalDate, LocalDateTime, ZonedDateTime', category: 'superseded',
668
+ },
669
+ {
670
+ pattern: /\bnew\s+Vector\s*[<(]/,
671
+ api: 'Vector', reason: 'Legacy synchronized collection — poor performance',
672
+ replacement: 'ArrayList (or Collections.synchronizedList())', category: 'superseded',
673
+ },
674
+ {
675
+ pattern: /\bnew\s+Hashtable\s*[<(]/,
676
+ api: 'Hashtable', reason: 'Legacy synchronized map — poor performance',
677
+ replacement: 'HashMap (or ConcurrentHashMap)', category: 'superseded',
678
+ },
679
+ {
680
+ pattern: /\bnew\s+Stack\s*[<(]/,
681
+ api: 'Stack', reason: 'Legacy class — extends Vector unnecessarily',
682
+ replacement: 'Deque<> (ArrayDeque) with push/pop', category: 'superseded',
683
+ },
684
+ {
685
+ pattern: /\bnew\s+StringBuffer\s*\(/,
686
+ api: 'StringBuffer', reason: 'Unnecessarily synchronized — slower than StringBuilder',
687
+ replacement: 'StringBuilder (unless thread safety needed)', category: 'superseded',
688
+ },
689
+ {
690
+ pattern: /\.getYear\s*\(\s*\)(?!.*java\.time)/,
691
+ api: 'Date.getYear()', reason: 'Deprecated since JDK 1.1 — returns year - 1900',
692
+ replacement: 'LocalDate.now().getYear()', category: 'superseded',
693
+ },
694
+ {
695
+ pattern: /Thread\.stop\s*\(/i,
696
+ api: 'Thread.stop()', reason: 'Deprecated — unsafe, can corrupt objects',
697
+ replacement: 'Thread.interrupt() with cooperative checking', category: 'security',
698
+ },
699
+ {
700
+ pattern: /Thread\.destroy\s*\(|Thread\.suspend\s*\(|Thread\.resume\s*\(/,
701
+ api: 'Thread.destroy/suspend/resume()', reason: 'Deprecated — deadlock-prone',
702
+ replacement: 'Thread.interrupt() and wait/notify', category: 'removed',
703
+ },
704
+ {
705
+ pattern: /Runtime\.runFinalizersOnExit\s*\(/,
706
+ api: 'Runtime.runFinalizersOnExit()', reason: 'Deprecated — inherently unsafe',
707
+ replacement: 'Runtime shutdown hooks or try-with-resources', category: 'removed',
708
+ },
709
+ {
710
+ pattern: /\bfinalize\s*\(\s*\)\s*(?:throws|\{)/,
711
+ api: 'finalize()', reason: 'Deprecated since Java 9 (JEP 421) — for removal',
712
+ replacement: 'Cleaner or try-with-resources (AutoCloseable)', category: 'superseded',
713
+ },
714
+ {
715
+ pattern: /\bnew\s+Integer\s*\(|new\s+Long\s*\(|new\s+Double\s*\(|new\s+Boolean\s*\(|new\s+Float\s*\(/,
716
+ api: 'new Integer/Long/Double/Boolean/Float()', reason: 'Deprecated since Java 9 — valueOf preferred',
717
+ replacement: 'Integer.valueOf(), autoboxing, or parse methods', category: 'superseded',
718
+ },
719
+ {
720
+ pattern: /\bSecurityManager\b/,
721
+ api: 'SecurityManager', reason: 'Deprecated for removal since Java 17 (JEP 411)',
722
+ replacement: 'No direct replacement — use OS-level security', category: 'removed',
723
+ },
724
+ ];