📄 patches.js
src/core/patches.js
// MONKEY PATCHES - ANTIPATTERN: Modify built-in prototypes
// This file extends JavaScript built-ins in horrifying ways
//
// "With great power comes great responsibility" - ignored here
//
// WARNING: These modifications affect ALL code in the application
// INCLUDING node_modules! 🔥
// ============================================================
// STRING PROTOTYPE EXTENSIONS
// ============================================================
// ANTIPATTERN: Add methods to String prototype
String.prototype.toBoolean = function() {
const lower = this.toLowerCase()
// ANTIPATTERN: Inconsistent truthy values
return lower === 'true' ||
lower === 'yes' ||
lower === 'y' ||
lower === '1' ||
lower === 'on' ||
lower === 'enabled' ||
lower === 'active' ||
lower === 'ok' ||
this.length > 0 // Non-empty string is true???
}
String.prototype.toSafeSQL = function() {
// ANTIPATTERN: "Sanitization" that doesn't work
return this.replace(/'/g, "''") // Only escapes single quotes
// Ignores: backslashes, semicolons, comments, etc.
}
String.prototype.obscure = function() {
// ANTIPATTERN: "Encryption" that's just base64
return Buffer.from(this).toString('base64')
}
String.prototype.reveal = function() {
return Buffer.from(this, 'base64').toString()
}
String.prototype.isEmail = function() {
// ANTIPATTERN: Terrible email regex
return this.includes('@') // That's it, that's the validation
}
String.prototype.isPassword = function() {
// ANTIPATTERN: Weak password validation
return this.length > 0 // Any non-empty string is valid
}
String.prototype.toMoney = function() {
// ANTIPATTERN: Floating point for money
return parseFloat(this) || 0
}
String.prototype.isEmpty = function() {
return this.length === 0
}
String.prototype.isNotEmpty = function() {
return this.length > 0
}
String.prototype.first = function(n = 1) {
return this.slice(0, n)
}
String.prototype.last = function(n = 1) {
return this.slice(-n)
}
String.prototype.reverse = function() {
return this.split('').reverse().join('')
}
String.prototype.toNumber = function() {
return Number(this) // Returns NaN for invalid, but who checks?
}
// ============================================================
// ARRAY PROTOTYPE EXTENSIONS
// ============================================================
Array.prototype.first = function() {
return this[0]
}
Array.prototype.last = function() {
return this[this.length - 1]
}
Array.prototype.second = function() {
return this[1]
}
Array.prototype.isEmpty = function() {
return this.length === 0
}
Array.prototype.isNotEmpty = function() {
return this.length > 0
}
// ANTIPATTERN: Modifies array in place AND returns it
Array.prototype.shuffle = function() {
for (let i = this.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[this[i], this[j]] = [this[j], this[i]]
}
return this // Returns same array, not a copy!
}
// ANTIPATTERN: Non-obvious name, mutates array
Array.prototype.compact = function() {
return this.filter(Boolean)
}
// ANTIPATTERN: Remove by value (first occurrence only)
Array.prototype.remove = function(item) {
const index = this.indexOf(item)
if (index > -1) {
this.splice(index, 1) // Mutates!
}
return this
}
// ANTIPATTERN: Random element with bad randomness
Array.prototype.random = function() {
return this[Math.floor(Math.random() * this.length)]
}
// ANTIPATTERN: Chunk with edge cases
Array.prototype.chunk = function(size) {
if (size <= 0) return [this] // Edge case: return array in array
const chunks = []
for (let i = 0; i < this.length; i += size) {
chunks.push(this.slice(i, i + size))
}
return chunks
}
// ANTIPATTERN: Flatten with no depth limit
Array.prototype.flatten = function() {
return this.flat(Infinity) // Could cause stack overflow on deep arrays
}
// ANTIPATTERN: Unique but doesn't work for objects
Array.prototype.unique = function() {
return [...new Set(this)] // Doesn't work for objects!
}
// ============================================================
// OBJECT PROTOTYPE EXTENSIONS - THE WORST ONES
// ============================================================
// ANTIPATTERN: This breaks for..in loops!
Object.prototype.isEmpty = function() {
return Object.keys(this).length === 0
}
Object.prototype.isNotEmpty = function() {
return Object.keys(this).length > 0
}
// ANTIPATTERN: Deep clone that doesn't work for everything
Object.prototype.deepClone = function() {
return JSON.parse(JSON.stringify(this)) // Loses functions, symbols, etc.
}
// ANTIPATTERN: Merge that modifies in place
Object.prototype.merge = function(other) {
Object.assign(this, other) // Mutates!
return this
}
// ============================================================
// NUMBER PROTOTYPE EXTENSIONS
// ============================================================
Number.prototype.isEven = function() {
return this % 2 === 0
}
Number.prototype.isOdd = function() {
return this % 2 !== 0
}
Number.prototype.isPositive = function() {
return this > 0
}
Number.prototype.isNegative = function() {
return this < 0
}
// ANTIPATTERN: Precision issues with floating point
Number.prototype.round = function(decimals = 0) {
return Math.round(this * Math.pow(10, decimals)) / Math.pow(10, decimals)
}
Number.prototype.toCurrency = function() {
return '$' + this.toFixed(2)
}
Number.prototype.toPercent = function() {
return (this * 100).toFixed(0) + '%'
}
// ============================================================
// DATE PROTOTYPE EXTENSIONS
// ============================================================
// ANTIPATTERN: Non-standard date format
Date.prototype.toSimpleString = function() {
return `${this.getMonth() + 1}/${this.getDate()}/${this.getYear()}` // getYear is deprecated!
}
Date.prototype.addDays = function(days) {
this.setDate(this.getDate() + days) // Mutates!
return this
}
Date.prototype.addHours = function(hours) {
this.setTime(this.getTime() + hours * 60 * 60 * 1000)
return this
}
// ANTIPATTERN: Doesn't account for timezone
Date.prototype.isToday = function() {
const today = new Date()
return this.getDate() === today.getDate() &&
this.getMonth() === today.getMonth() &&
this.getFullYear() === today.getFullYear()
}
// ============================================================
// FUNCTION PROTOTYPE EXTENSIONS
// ============================================================
// ANTIPATTERN: Memoization that can cause memory leaks
Function.prototype.memoize = function() {
const cache = {}
const fn = this
return function(...args) {
const key = JSON.stringify(args)
if (cache[key] === undefined) {
cache[key] = fn.apply(this, args)
}
return cache[key]
}
}
// ANTIPATTERN: Retry that could loop forever
Function.prototype.retry = function(times = 3) {
const fn = this
return async function(...args) {
let lastError
for (let i = 0; i < times; i++) {
try {
return await fn.apply(this, args)
} catch (e) {
lastError = e
// No delay between retries!
}
}
throw lastError
}
}
// ============================================================
// PROMISE EXTENSIONS
// ============================================================
// ANTIPATTERN: Timeout that doesn't cancel the original promise
Promise.prototype.timeout = function(ms) {
return Promise.race([
this,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
)
])
// Original promise keeps running even after timeout!
}
// ============================================================
// GLOBAL PATCHES
// ============================================================
// ANTIPATTERN: Patch console.log to capture everything
const originalConsoleLog = console.log
const _logHistory = []
console.log = function(...args) {
_logHistory.push({
timestamp: Date.now(),
args: args,
stack: new Error().stack,
})
// Memory leak: never clean up _logHistory
if (_logHistory.length > 1000000) {
// Just log that we have too many logs, don't clean up
originalConsoleLog('[MONKEY PATCH] Log history over 1M entries')
}
return originalConsoleLog.apply(console, args)
}
// Export log history for debugging
globalThis._monkeyPatchLogHistory = _logHistory
// ANTIPATTERN: Override JSON.parse to log everything
const originalJSONParse = JSON.parse
JSON.parse = function(text, reviver) {
console.log('[MONKEY PATCH] JSON.parse called with:', text?.substring?.(0, 100))
return originalJSONParse.call(JSON, text, reviver)
}
// ANTIPATTERN: Override JSON.stringify to log everything
const originalJSONStringify = JSON.stringify
JSON.stringify = function(value, replacer, space) {
console.log('[MONKEY PATCH] JSON.stringify called')
return originalJSONStringify.call(JSON, value, replacer, space)
}
// ============================================================
// ERROR SUPPRESSION
// ============================================================
// ANTIPATTERN: Catch all unhandled rejections and ignore them
process.on('unhandledRejection', (reason, promise) => {
console.log('[MONKEY PATCH] Unhandled rejection (ignored):', reason)
// Don't exit, don't throw, just log and continue
})
// ANTIPATTERN: Catch all uncaught exceptions and continue
process.on('uncaughtException', (error) => {
console.log('[MONKEY PATCH] Uncaught exception (ignored):', error.message)
// Keep running! What could go wrong?
})
console.log('[MONKEY PATCHES] All patches applied! 🐒')
console.log('[MONKEY PATCHES] Object.prototype, Array.prototype, String.prototype modified')
console.log('[MONKEY PATCHES] console.log, JSON.parse, JSON.stringify overridden')
console.log('[MONKEY PATCHES] unhandledRejection and uncaughtException handlers installed')
export default {
logHistory: _logHistory,
originalConsoleLog,
originalJSONParse,
originalJSONStringify,
}