roast-my-codebase 1.3.1 → 1.3.3

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 (2) hide show
  1. package/dist/index.js +348 -66
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5980,7 +5980,16 @@ var largeFileRoasts = [
5980
5980
  "This file has a higher line count than the project's test suite.",
5981
5981
  "Opening this file in vim is a commitment.",
5982
5982
  "The search results for this file take longer than the search results for the whole project.",
5983
- "One day someone will split this file into sensible modules. Today is not that day. Neither was yesterday."
5983
+ "One day someone will split this file into sensible modules. Today is not that day. Neither was yesterday.",
5984
+ // meme refs
5985
+ "It's over 9000 lines. At this point it's a power level, not a file.",
5986
+ "We don't split files here. \u{1F440}",
5987
+ "Nobody: ... This file: *adds 200 more lines*",
5988
+ "404: Single Responsibility not found.",
5989
+ "This file is built different. Unfortunately.",
5990
+ "This file said 'why have many file when one file do trick.'",
5991
+ "Jon Snow knows nothing about this file. Neither does anyone else.",
5992
+ "Main character energy. Every function wants to be the hero."
5984
5993
  ];
5985
5994
  var extremeFileRoasts = [
5986
5995
  "This file has more lines than a congressional hearing transcript.",
@@ -5989,7 +5998,13 @@ var extremeFileRoasts = [
5989
5998
  "This file is so large that reading it is considered cardio.",
5990
5999
  "2000 lines. One file. Zero mercy.",
5991
6000
  "This file has geological strata. The bottom layers date to a different framework.",
5992
- "Splitting this file would be an act of mercy."
6001
+ "Splitting this file would be an act of mercy.",
6002
+ // meme refs
6003
+ "This is fine. \u{1F525} (It is not fine.)",
6004
+ "This file said 'hold my semicolon' and never stopped.",
6005
+ "Drake pointing meme: splitting into modules \u274C ... one file with 2000 lines \u2705",
6006
+ "The power of this file is OVER 9000 lines. Consider that a bad sign.",
6007
+ "One does not simply open this file in a code review."
5993
6008
  ];
5994
6009
  var largeFileWarningRoasts = [
5995
6010
  "This file is testing the definition of 'single responsibility'.",
@@ -6018,7 +6033,15 @@ var todoRoasts = [
6018
6033
  "A TODO without a ticket number is just a dream.",
6019
6034
  "These comment markers are a conversation between past you and future you. Future you is not happy.",
6020
6035
  "The TODO density correlates with deadline pressure. The graph is not flattering.",
6021
- "HACK: this is the one that makes the whole thing work. Don't touch it."
6036
+ "HACK: this is the one that makes the whole thing work. Don't touch it.",
6037
+ // meme refs
6038
+ "This is fine. *TODO count increases* This is fine.",
6039
+ "Two buttons meme: fix the bug now \u274C ... write TODO and run \u2705",
6040
+ `"I'll fix it later" \u2014 said in 2019. The TODO is still there.`,
6041
+ "The TODO is free real estate for Future You's problems.",
6042
+ "Task failed successfully \u2014 HACK comment is now the only documentation.",
6043
+ "These FIXMEs are giving 'we'll fix it in post' energy.",
6044
+ "// TODO: understand why this works \u2014 commit message from 3 years ago, still unresolved."
6022
6045
  ];
6023
6046
  var dependencyRoasts = [
6024
6047
  "This package.json reads like a phone book.",
@@ -6037,7 +6060,15 @@ var dependencyRoasts = [
6037
6060
  "Every dependency is a supply chain. Every package in node_modules is a trust decision.",
6038
6061
  "package-lock.json hasn't been committed. The build is not reproducible. This is fine.",
6039
6062
  "Some of these packages have been deprecated. Some of the deprecations have been deprecated.",
6040
- "You have a dependency for left-padding. The lesson was not learned."
6063
+ "You have a dependency for left-padding. The lesson was not learned.",
6064
+ // meme refs
6065
+ "node_modules is 300MB. The actual app is 4KB. We do a little installing.",
6066
+ "npm install: hold on, let me download the entire internet real quick.",
6067
+ "This is giving 'just one more dependency' energy from someone who said that 47 times.",
6068
+ "Little Bobby Tables' cousin, Little Bobby `npm install --save`.",
6069
+ "rm -rf node_modules and pray. The classic.",
6070
+ "Unopened dependency. Collecting dust. Paying rent. Living rent-free in your bundle.",
6071
+ "This package's last commit was when Stack Overflow still had a dark mode beta."
6041
6072
  ];
6042
6073
  var circularRoasts = [
6043
6074
  "These files are in a codependent relationship.",
@@ -6054,7 +6085,14 @@ var circularRoasts = [
6054
6085
  "Circular dependencies are easy to introduce and expensive to remove. You're in the expensive part now.",
6055
6086
  "These files are so entangled they should be refactored together or not at all.",
6056
6087
  "The dependency inversion principle exists specifically to prevent this situation.",
6057
- "This circular dependency has probably already caused a subtle initialization order bug somewhere."
6088
+ "This circular dependency has probably already caused a subtle initialization order bug somewhere.",
6089
+ // meme refs
6090
+ "A imports B, B imports A. It's giving 'chicken and egg' but worse.",
6091
+ "Ouroboros architecture: the module that imports itself into oblivion.",
6092
+ "The circle of life, but for spaghetti code.",
6093
+ "This is the 'they were roommates' of software architecture.",
6094
+ "Modules: we import each other. Graph theorists: I've never seen anything like this.",
6095
+ "Webpack looked at this import graph and chose violence."
6058
6096
  ];
6059
6097
  var structureRoasts = [
6060
6098
  "This folder structure would make a spelunker nervous.",
@@ -6072,7 +6110,14 @@ var structureRoasts = [
6072
6110
  "A folder called 'new' is now the oldest folder in the project.",
6073
6111
  "This nesting depth would be impressive if it were intentional.",
6074
6112
  "The project structure suggests it was organized by someone who left before finishing.",
6075
- "helpers/, utils/, common/, shared/ \u2014 four folders, zero clarity, maximum confusion."
6113
+ "helpers/, utils/, common/, shared/ \u2014 four folders, zero clarity, maximum confusion.",
6114
+ // meme refs
6115
+ "Folder named 'final'. Folder named 'final_v2'. Folder named 'final_ACTUAL'. Classic.",
6116
+ "This structure has more layers than a Shrek metaphor.",
6117
+ "The utils/ folder is just a junk drawer that learned to code.",
6118
+ "Nobody knows what's in misc/. Nobody goes into misc/. We respect misc/.",
6119
+ "This directory structure was designed by someone who had 'just one more idea.'",
6120
+ "The folder is named 'temp'. It is 4 years old."
6076
6121
  ];
6077
6122
  var complexityRoasts = [
6078
6123
  "This function has more branches than a forest.",
@@ -6093,7 +6138,17 @@ var complexityRoasts = [
6093
6138
  "The code path through this function visits twelve states. Most of them are undefined.",
6094
6139
  "This is the function everyone understands on Monday and nobody understands on Friday.",
6095
6140
  "Whoever wrote this knew exactly what they were doing. That's the alarming part.",
6096
- "The indentation alone tells a story. It's a tragedy."
6141
+ "The indentation alone tells a story. It's a tragedy.",
6142
+ // meme refs
6143
+ "This function has more branches than a Marvel multiverse plotline.",
6144
+ "Gru's plan: write simple function \u2192 add one more condition \u2192 add one more condition \u2192 this.",
6145
+ "Cyclomatic complexity over 20: we do a little suffering.",
6146
+ "The nested ifs go so deep they have their own weather system.",
6147
+ "Big if true. Bigger if false. Enormous if undefined.",
6148
+ "This function is the 'we have clean code at home' of clean code.",
6149
+ "Nobody: ... this function: *adds an else-if*",
6150
+ "It's giving 'I just need to handle one more edge case' from 47 edge cases ago.",
6151
+ "Reading this function is a lore dump nobody asked for."
6097
6152
  ];
6098
6153
  var duplicateRoasts = [
6099
6154
  "Copy-paste is not a design pattern.",
@@ -6113,7 +6168,14 @@ var duplicateRoasts = [
6113
6168
  "This code was copied before it was debugged. Now the bug lives in three places.",
6114
6169
  "Three implementations of the same function suggests a communication problem as much as a code problem.",
6115
6170
  "Copy-paste without abstraction: writing the same bug faster.",
6116
- "The original function is over there. These are its consequences."
6171
+ "The original function is over there. These are its consequences.",
6172
+ // meme refs
6173
+ "Ctrl+C, Ctrl+V, Ctrl+regret.",
6174
+ "The original and the remix. Neither is correct.",
6175
+ "This is the 'we have abstraction at home' of abstraction.",
6176
+ "Same function, three locations. Pick your fighter (they all have the same bug).",
6177
+ "Whoever did this has never heard of functions. Introduce yourself.",
6178
+ "Copy-paste detected. Future junior dev crying about it in 6 months: loading..."
6117
6179
  ];
6118
6180
  var deadExportRoasts = [
6119
6181
  "These exports are shouting into the void.",
@@ -6133,7 +6195,13 @@ var deadExportRoasts = [
6133
6195
  "Dead exports are how APIs accumulate surface area without adding value.",
6134
6196
  "The export keyword is load-bearing in theory. In this case, it's decoration.",
6135
6197
  "Somebody exported this for future use. The future arrived. The function was not consulted.",
6136
- "This export is proof that 'just in case' is the most expensive reason to keep code."
6198
+ "This export is proof that 'just in case' is the most expensive reason to keep code.",
6199
+ // meme refs
6200
+ "404: importer not found.",
6201
+ "This export said 'I'm ready' and then waited forever.",
6202
+ "Posting on the internet vs this export: both got zero engagement.",
6203
+ "exported for future use. The future said 'no thanks.'",
6204
+ "This function is the 'reply all' of the codebase \u2014 present everywhere, needed nowhere."
6137
6205
  ];
6138
6206
  var typeSafetyRoasts = [
6139
6207
  "TypeScript is just JavaScript with extra steps at this rate.",
@@ -6154,7 +6222,15 @@ var typeSafetyRoasts = [
6154
6222
  "The type system is not your enemy. But you've treated it like one.",
6155
6223
  "`any` as a parameter type means this function accepts everything and promises nothing.",
6156
6224
  "You've used TypeScript as a syntax highlighter. Understandable. Wrong.",
6157
- "The runtime crash TypeScript would have caught is worth more than the time you saved ignoring it."
6225
+ "The runtime crash TypeScript would have caught is worth more than the time you saved ignoring it.",
6226
+ // meme refs
6227
+ "TypeScript: am I a joke to you?",
6228
+ "`any` is just JavaScript in a trench coat pretending to be TypeScript.",
6229
+ "We have types at home. The types at home: `any`.",
6230
+ "@ts-ignore: the developer equivalent of covering your eyes and saying 'it's fine.'",
6231
+ "Using TypeScript without types is like buying a gym membership and never going. We've all done it. It's still wrong.",
6232
+ "The `any` count in this file is giving 'I learned TypeScript in an afternoon' energy.",
6233
+ "TypeScript tried to warn you. You put on noise-cancelling headphones."
6158
6234
  ];
6159
6235
  var gitChurnRoasts = [
6160
6236
  "This file changes more often than JavaScript frameworks.",
@@ -6173,7 +6249,14 @@ var gitChurnRoasts = [
6173
6249
  "git blame on this file is a palimpsest of regret.",
6174
6250
  "Frequent changes without refactoring is how complexity accumulates in small increments.",
6175
6251
  "This file changes in every sprint. Consider whether 'ownership' is the right word for this relationship.",
6176
- "The diff history for this file is longer than the file itself."
6252
+ "The diff history for this file is longer than the file itself.",
6253
+ // meme refs
6254
+ "git blame: a horror story in commit messages.",
6255
+ "This file changes so often it has its own fan base on Slack.",
6256
+ "Quantity of commits \u2260 quality of code. Exhibit A.",
6257
+ "Six devs, zero docs, infinite git history. A classic.",
6258
+ "Every PR touches this file. Nobody knows why. Nobody asks.",
6259
+ "This file has seen more rewrites than a startup pitch deck."
6177
6260
  ];
6178
6261
  var securityRoasts = [
6179
6262
  "Secrets in git. Because what could go wrong?",
@@ -6192,7 +6275,15 @@ var securityRoasts = [
6192
6275
  "The credential rotation email is going to be uncomfortable.",
6193
6276
  "Security through obscurity is not a layer of the defense-in-depth model.",
6194
6277
  "The threat model for this code assumes everyone is friendly. They are not.",
6195
- "Your .env file is now a historical document. Congratulations."
6278
+ "Your .env file is now a historical document. Congratulations.",
6279
+ // meme refs
6280
+ "Little Bobby Tables visited your repo. He felt at home.",
6281
+ "The hackers found it before you did. They always do.",
6282
+ "Pushed API key to GitHub. 47 bots cloned it. This is fine. \u{1F525}",
6283
+ "AWS bill incoming. Origin: mysterious. Cause: this commit.",
6284
+ "This is not a security vulnerability. It is a free trial for attackers.",
6285
+ "Your secrets are in git. They are immutable. They are eternal. They will outlive you.",
6286
+ "Sir, this is a Wendy's \u2014 and also your database password is in plaintext."
6196
6287
  ];
6197
6288
  var testCoverageRoasts = [
6198
6289
  "Tests are optional, right? Right?",
@@ -6212,7 +6303,15 @@ var testCoverageRoasts = [
6212
6303
  "At some point a regression will be introduced and traced back to this file. Book it.",
6213
6304
  "This module has been running on faith since it was written.",
6214
6305
  "The test pyramid has a foundation. This project skipped the foundation.",
6215
- "Every function here is one undefined behavior away from a production incident."
6306
+ "Every function here is one undefined behavior away from a production incident.",
6307
+ // meme refs
6308
+ "Works on my machine \u2122",
6309
+ "No tests: the original move fast and break things strategy.",
6310
+ "Ship it and pray \u2014 a time-honoured tradition.",
6311
+ "This code is in production and has never met a test. Respect the confidence.",
6312
+ "The only test for this function is a 3am PagerDuty alert.",
6313
+ "QA: did you test this? Dev: it compiled. QA: ...",
6314
+ "Bugs found in production: 0 (so far). Tests written: also 0. Coincidence? No."
6216
6315
  ];
6217
6316
  var frameworkRoasts = [
6218
6317
  "Next.js best practices are more like Next.js suggestions, apparently.",
@@ -6223,7 +6322,13 @@ var frameworkRoasts = [
6223
6322
  "A missing error boundary is a gift to your users \u2014 of a white screen.",
6224
6323
  "Server components with client hooks: the temporal paradox of React.",
6225
6324
  "SEO is hard. Missing metadata makes it harder for no reason.",
6226
- "React has conventions. They're not enforced. That's the trap."
6325
+ "React has conventions. They're not enforced. That's the trap.",
6326
+ // meme refs
6327
+ "The white screen of death is just an undocumented feature.",
6328
+ "useEffect with no dependency array: runs on every render, symptoms TBD.",
6329
+ "We have a framework. We have opinions. We have ignored both.",
6330
+ "Next.js docs said don't do this. This is the 'hold my beer' commit.",
6331
+ "React: just use components! This codebase: bold of you to assume."
6227
6332
  ];
6228
6333
  var verdicts = {
6229
6334
  excellent: [
@@ -6234,7 +6339,12 @@ var verdicts = {
6234
6339
  "This is what happens when someone actually enforces code review.",
6235
6340
  "Suspiciously healthy. Did you hide the bad files somewhere?",
6236
6341
  "The linter is satisfied. The linter is never satisfied. This is a good sign.",
6237
- "Clean enough to show your colleagues. Rare."
6342
+ "Clean enough to show your colleagues. Rare.",
6343
+ // meme refs
6344
+ "Certified hood classic. Ship it.",
6345
+ "No notes. Genuinely no notes. This is uncomfortable.",
6346
+ "10/10, would git clone again.",
6347
+ "The senior dev opened the PR and said nothing. That's the highest praise."
6238
6348
  ],
6239
6349
  good: [
6240
6350
  "Solid work. A few rough edges, but nothing that keeps you up at night.",
@@ -6244,7 +6354,12 @@ var verdicts = {
6244
6354
  "You've got 80% of the good habits. The other 20% is where complexity lives.",
6245
6355
  "Better than average, which is a low bar that you cleared with room to spare.",
6246
6356
  "A codebase that a new hire could navigate without a guide. That's saying something.",
6247
- "Good bones. Some questionable wallpaper. Still livable."
6357
+ "Good bones. Some questionable wallpaper. Still livable.",
6358
+ // meme refs
6359
+ "Pretty good. Could be worse. Has been worse.",
6360
+ "A solid B+. Your CS professor would nod.",
6361
+ "Not bad at all. The bar was low but you cleared it with style.",
6362
+ "We're so back. Almost."
6248
6363
  ],
6249
6364
  fair: [
6250
6365
  "Your codebase is at that stage where 'refactor sprint' keeps getting postponed.",
@@ -6255,7 +6370,12 @@ var verdicts = {
6255
6370
  "There's a refactor conversation waiting to happen. Probably in Q3.",
6256
6371
  "This codebase is fine in the way that a car with 180k miles is fine.",
6257
6372
  "Holding together. Possibly through social cohesion and mutual agreement not to look too closely.",
6258
- "The code ships. The code also shivers slightly when you touch the old parts."
6373
+ "The code ships. The code also shivers slightly when you touch the old parts.",
6374
+ // meme refs
6375
+ "It's giving 'works until it doesn't.'",
6376
+ "Mid. Loveable mid, but mid.",
6377
+ "This is fine. \u{1F525} (Mostly fine. Borderline fine.)",
6378
+ "The vibe is: shipping features faster than addressing the findings from last quarter."
6259
6379
  ],
6260
6380
  risky: [
6261
6381
  "Your codebase is one bad merge away from a support group.",
@@ -6266,7 +6386,13 @@ var verdicts = {
6266
6386
  "The tech debt has compounded interest. It now has opinions about your architecture.",
6267
6387
  "Not broken. Just... haunted.",
6268
6388
  "Production is stable. For now. Don't ask what 'for now' means.",
6269
- "You're one refactor away from discovering why nobody refactored it before."
6389
+ "You're one refactor away from discovering why nobody refactored it before.",
6390
+ // meme refs
6391
+ "This codebase is one `npm install` away from an existential crisis.",
6392
+ "It do be like that sometimes. It really do.",
6393
+ "Jenga tower, move 47. Your turn.",
6394
+ "The tech debt has filed for incorporation. It's a legal entity now.",
6395
+ "Chaos mode: partially activated."
6270
6396
  ],
6271
6397
  chaotic: [
6272
6398
  "This codebase is held together by hope and string literals.",
@@ -6277,156 +6403,245 @@ var verdicts = {
6277
6403
  "git log tells a story of hope, compromise, and eventual acceptance.",
6278
6404
  "Code this complex doesn't have bugs. It has 'undocumented features' and 'emergent behavior'.",
6279
6405
  "Every function is load-bearing. You know this because removing one proved it.",
6280
- "This code has achieved something rare: it is simultaneously legacy and unsupported."
6406
+ "This code has achieved something rare: it is simultaneously legacy and unsupported.",
6407
+ // meme refs
6408
+ "This is fine. \u{1F525} (It is not fine. Nothing is fine.)",
6409
+ "We are so back. We have never been back. We will not be back.",
6410
+ "Bro thought he cooked. He did not cook.",
6411
+ "The boys are NOT thriving.",
6412
+ "This codebase said 'hold my beer' and never came back.",
6413
+ "404: architecture not found.",
6414
+ "It's giving 'written at 2am before a deadline and never touched again.'",
6415
+ "Chaotic neutral codebase. No laws. No gods. Just vibes and runtime errors."
6281
6416
  ]
6282
6417
  };
6283
6418
  var pythonTypeHintsRoasts = [
6284
6419
  "Type hints are optional in Python. So are brakes on a car, technically.",
6285
6420
  "Dynamic typing is great until your production server discovers the wrong type at 3 AM.",
6286
- "Type hints: because debugging at runtime is what keeps us young."
6421
+ "Type hints: because debugging at runtime is what keeps us young.",
6422
+ "Python without type hints: a mystery novel where every function is a surprise ending.",
6423
+ "This is fine until `str` shows up where `int` was expected at 3am on a Friday.",
6424
+ "mypy would like a word. mypy is very upset."
6287
6425
  ];
6288
6426
  var pythonImportRoasts = [
6289
6427
  "Wildcard imports: because you like playing 'guess which namespace that came from.'",
6290
6428
  "Deep relative imports: your codebase is spaghetti that imports other spaghetti.",
6291
- "from module import * \u2014 the programming equivalent of 'throw everything in and hope.'"
6429
+ "from module import * \u2014 the programming equivalent of 'throw everything in and hope.'",
6430
+ "from chaos import everything \u2014 this wildcard import described itself.",
6431
+ "Five levels of relative imports deep. We are so far from home."
6292
6432
  ];
6293
6433
  var pythonDocstringRoasts = [
6294
6434
  "Docstrings are optional. So is understanding your code in 6 months.",
6295
6435
  "Your functions are mysteries wrapped in enigmas. Add a docstring.",
6296
- "Self-documenting code is a myth. Your future self will thank you for docstrings."
6436
+ "Self-documenting code is a myth. Your future self will thank you for docstrings.",
6437
+ "No docstrings: the ancient art of leaving future teammates to suffer.",
6438
+ "This function's name is `process`. It processes. What? Mystery."
6297
6439
  ];
6298
6440
  var pythonSmellRoasts = [
6299
6441
  "Bare except: catching everything including your dignity.",
6300
6442
  "Mutable default arguments: the gift that keeps on mutating.",
6301
6443
  "This much global state makes singletons look elegant.",
6302
- "Your functions are nested deeper than your tech debt."
6444
+ "Your functions are nested deeper than your tech debt.",
6445
+ "bare except: the Pok\xE9mon Master of error handling \u2014 gotta catch 'em all.",
6446
+ "Global variables: because local scope is for people who plan ahead.",
6447
+ "This mutable default arg has been silently accumulating state since the first call. Good luck."
6303
6448
  ];
6304
6449
  var pythonSecurityRoasts = [
6305
- "eval() in Python: because you want hackers to feel welcome.",
6306
6450
  "pickle.load() from untrusted data is just exec() with extra steps.",
6307
6451
  "shell=True with user input: RCE as a feature, not a bug.",
6308
6452
  "SQL string formatting: Little Bobby Tables approves.",
6309
- "Hardcoded secrets in Python: because .env files are too mainstream."
6453
+ "Hardcoded secrets in Python: because .env files are too mainstream.",
6454
+ "Little Bobby Tables sends his regards to your f-string SQL query.",
6455
+ "shell=True and user input: the villain origin story for your production server.",
6456
+ "pickle from untrusted source: 'I have no idea what I'm deserializing and at this point I'm afraid to ask.'"
6310
6457
  ];
6311
6458
  var pythonDesignRoasts = [
6312
6459
  "This class has more methods than a Swiss Army knife has tools.",
6313
6460
  "A class with no methods is just a dict wearing a trench coat. Use @dataclass.",
6314
- "4+ parent classes: your MRO looks like a family tree from the Habsburgs."
6461
+ "4+ parent classes: your MRO looks like a family tree from the Habsburgs.",
6462
+ "God class spotted. It does everything. It knows everything. It will not be refactored.",
6463
+ "This class is a dict with anxiety. Use @dataclass.",
6464
+ "Six parent classes deep. Python's MRO is writing its resignation letter."
6315
6465
  ];
6316
6466
  var goErrorHandlingRoasts = [
6317
6467
  "Ignoring errors in Go is like ignoring check engine lights.",
6318
6468
  "_ = dangerousOperation() \u2014 the Go equivalent of 'it's fine.'",
6319
6469
  "Your error handling strategy appears to be 'hope.'",
6320
- "panic() in production: because graceful degradation is overrated."
6470
+ "panic() in production: because graceful degradation is overrated.",
6471
+ "if err != nil { _ = err } \u2014 the most chaotic thing you can do in Go.",
6472
+ "Go gives you errors. You gave them the silent treatment. They will not be silent forever.",
6473
+ "panic() and recover(): a horror movie where you already know the ending."
6321
6474
  ];
6322
6475
  var goLintRoasts = [
6323
6476
  "Unexported symbols don't need docs. Exported ones do. Guess which you forgot.",
6324
6477
  "Multiple init() functions: because one confusing startup sequence wasn't enough.",
6325
- "Go proverbs say 'a little copying is better than a little dependency.' You took that personally."
6478
+ "Go proverbs say 'a little copying is better than a little dependency.' You took that personally.",
6479
+ "Effective Go was written for a reason. This code is the reason.",
6480
+ "Multiple init() calls: startup order is now a choose-your-own-adventure."
6326
6481
  ];
6327
6482
  var rustUnsafeRoasts = [
6328
6483
  "unsafe {} \u2014 Rust's way of saying 'I know what I'm doing.' Do you, though?",
6329
6484
  "This much unsafe code defeats the purpose of choosing Rust.",
6330
- "The borrow checker can't save you if you keep bypassing it."
6485
+ "The borrow checker can't save you if you keep bypassing it.",
6486
+ "You chose Rust for memory safety and then wrote unsafe {}. Interesting arc.",
6487
+ "unsafe: I am speed. Also: I am undefined behaviour.",
6488
+ "The borrow checker tried to protect you. You said no. The segfault is coming."
6331
6489
  ];
6332
6490
  var rustClippyRoasts = [
6333
6491
  ".unwrap() everywhere: living dangerously, one None at a time.",
6334
6492
  "This much .clone() suggests a fundamental misunderstanding of ownership.",
6335
- "todo!() in production: the Rust equivalent of 'I'll fix it later.'"
6493
+ "todo!() in production: the Rust equivalent of 'I'll fix it later.'",
6494
+ ".unwrap() on user input: a panic waiting for its moment to shine.",
6495
+ "Clippy has 47 suggestions. You have 0 acknowledgements. Bold.",
6496
+ ".clone().clone().clone() \u2014 the memory is leaving the building."
6336
6497
  ];
6337
6498
  var javaSmellRoasts = [
6338
6499
  "This class has more methods than a phone book has entries.",
6339
6500
  "System.out.println in production \u2014 logging frameworks exist, you know.",
6340
6501
  "Empty catch blocks: because exceptions are just suggestions.",
6341
- "God classes: when Single Responsibility Principle is just a suggestion."
6502
+ "God classes: when Single Responsibility Principle is just a suggestion.",
6503
+ "AbstractSingletonProxyFactoryBean has entered the chat.",
6504
+ "System.out.println: Java's way of saying 'I'll add proper logging later.' Later never came.",
6505
+ "Empty catch block: the exception tried to tell you something. You covered your ears.",
6506
+ "This class does so much it should be paying rent in every microservice."
6342
6507
  ];
6343
6508
  var javaNamingRoasts = [
6344
6509
  "AbstractSingletonProxyFactoryBean called. It wants its naming convention back.",
6345
6510
  "Java naming conventions aren't optional. Even Java thinks so.",
6346
- "Your constant naming is more chaotic than your class hierarchy."
6511
+ "Your constant naming is more chaotic than your class hierarchy.",
6512
+ "IAbstractManagerFactoryHelperImpl: a name that describes everything and communicates nothing.",
6513
+ "Naming things is hard. This name suggests it wasn't attempted."
6347
6514
  ];
6348
6515
  var csharpSmellRoasts = [
6349
6516
  "#region is not architecture. It's a rug to sweep complexity under.",
6350
6517
  "Console.WriteLine in production? ILogger is right there.",
6351
- "This class is so large it needs its own table of contents."
6518
+ "This class is so large it needs its own table of contents.",
6519
+ "#region: collapsing complexity doesn't remove it, it just makes it easier to ignore.",
6520
+ "Console.WriteLine: the poor man's Application Insights.",
6521
+ "This class is doing so much it should file as an LLC."
6352
6522
  ];
6353
6523
  var csharpAsyncRoasts = [
6354
6524
  "async void: the fire-and-forget-and-pray pattern.",
6355
6525
  ".Result and .Wait() \u2014 deadlocks as a service.",
6356
- "Sync-over-async: because who needs scalability anyway."
6526
+ "Sync-over-async: because who needs scalability anyway.",
6527
+ "async void: exceptions from this method disappear into the void. That's not a metaphor.",
6528
+ ".Result on an async method: congratulations, you just reinvented blocking IO.",
6529
+ "The thread pool called. It's exhausted. Literally."
6357
6530
  ];
6358
6531
  var vueIssuesRoasts = [
6359
6532
  "Options API in Vue 3: writing Vue 2 code in a Vue 3 world.",
6360
6533
  "v-for without :key \u2014 Vue is now doing the hokey pokey trying to track your list.",
6361
6534
  "Deep watcher? Congratulations, you've opted into re-running everything for no reason.",
6362
- "This component watches everything deeply. Your CPU feels watched."
6535
+ "This component watches everything deeply. Your CPU feels watched.",
6536
+ "v-for without :key: Vue is trying its best. You are not helping.",
6537
+ "Options API in a Vue 3 project is nostalgia as a code smell.",
6538
+ "This deep watcher is re-running on every keystroke. Your laptop fan agrees."
6363
6539
  ];
6364
6540
  var angularIssuesRoasts = [
6365
6541
  "No OnPush? Angular checks this component like a paranoid security guard \u2014 constantly.",
6366
6542
  "Direct DOM manipulation in Angular: ElementRef and prayers.",
6367
6543
  "(event: any) \u2014 typed strictly, except when it matters.",
6368
- "Without OnPush, change detection runs so often it should get overtime pay."
6544
+ "Without OnPush, change detection runs so often it should get overtime pay.",
6545
+ "Angular's change detection is thorough. Without OnPush, it's also relentless.",
6546
+ "ElementRef and direct DOM access: we have a renderer, we have signals, and yet.",
6547
+ "Typed strictly everywhere except the event handler. Classic."
6369
6548
  ];
6370
6549
  var svelteIssuesRoasts = [
6371
6550
  "Reactive side effects: your $: block is doing more work than your actual functions.",
6372
6551
  "A button without aria-label is just a mystery rectangle to screen readers.",
6373
6552
  "Svelte is supposed to simplify things. This fetch() in $: disagrees.",
6374
- "Your reactive statements have more side effects than a clearance-sale medication."
6553
+ "Your reactive statements have more side effects than a clearance-sale medication.",
6554
+ "This $: block runs every time anything changes. It will run a lot.",
6555
+ "A button with no label is a UX mystery box. Screen readers hate mystery boxes.",
6556
+ "Svelte: the framework that compiles away the framework. This code is fighting back."
6375
6557
  ];
6376
6558
  var expressIssuesRoasts = [
6377
6559
  "No error handler in Express \u2014 every unhandled error is a coin flip with production.",
6378
6560
  "No rate limiting: your API is accepting all requests, including the ones from bots.",
6379
6561
  "Synchronous file I/O in a route handler: welcome to the event loop queue.",
6380
- "One bad request handler away from taking down the whole server."
6562
+ "One bad request handler away from taking down the whole server.",
6563
+ "No rate limiting: your API welcomes bots, scrapers, and bad actors with open arms.",
6564
+ "fs.readFileSync in a route handler: every request now blocks the entire server. Nice.",
6565
+ "Unhandled promise rejection in a route: the server will crash. It's not a matter of if.",
6566
+ "Express error handler missing: errors go to /dev/null and production goes down."
6381
6567
  ];
6382
6568
  var fastapiIssuesRoasts = [
6383
6569
  "Missing response_model: FastAPI's docs page is just vibes now.",
6384
6570
  "Sync endpoint in FastAPI \u2014 you picked the async framework and blocked the event loop anyway.",
6385
6571
  "POST without status_code: the client has to guess if it worked. Good luck.",
6386
- "No response_model means no validation, no docs, and no regrets \u2014 until there are regrets."
6572
+ "No response_model means no validation, no docs, and no regrets \u2014 until there are regrets.",
6573
+ "FastAPI without response_model: the Swagger docs are now a work of abstract fiction.",
6574
+ "def instead of async def in FastAPI: you picked the async framework and turned it off.",
6575
+ "POST returning 200 for a created resource. HTTP status codes are suggestions, apparently."
6387
6576
  ];
6388
6577
  var depAuditRoasts = [
6389
6578
  "Your dependencies have vulnerabilities. Security is just a vibe anyway.",
6390
6579
  "npm audit called \u2014 it's not happy about your life choices.",
6391
6580
  "CVEs in production: turning 'works on my machine' into 'hacked on your machine'.",
6392
- "Supply chain attack? More like supply chain welcome mat."
6581
+ "Supply chain attack? More like supply chain welcome mat.",
6582
+ "npm audit: a cry for help you keep dismissing.",
6583
+ "CVE in a prod dependency: the gift that ships with your application.",
6584
+ "Your supply chain has more holes than the plot of a heist movie.",
6585
+ "The vulnerability scanner found issues. You found reasons to ignore them. One of you is right."
6393
6586
  ];
6394
6587
  var depOutdatedRoasts = [
6395
6588
  "These packages haven't been updated since the last ice age.",
6396
6589
  "npm outdated: a love letter from the past.",
6397
6590
  "Your dependencies are aging like milk, not wine.",
6398
- "These major version upgrades won't do themselves. (They will not, in fact, do themselves.)"
6591
+ "These major version upgrades won't do themselves. (They will not, in fact, do themselves.)",
6592
+ "Some of these packages were last updated when tabs vs spaces was still a debate.",
6593
+ "npm outdated is running a eulogy for your dependencies.",
6594
+ "Major version behind: the changelog is long, the breaking changes are many, the update is overdue.",
6595
+ "These packages are so outdated they remember when JavaScript was just for form validation."
6399
6596
  ];
6400
6597
  var rubyRoasts = [
6401
6598
  "Ruby: where every class is a God class waiting to happen.",
6402
6599
  "This method is so complex it needs its own retrospective.",
6403
- "eval() in Ruby: because you miss the XSS vulnerabilities from your PHP days.",
6404
- "No frozen_string_literal? Your strings are living their best mutable life."
6600
+ "No frozen_string_literal? Your strings are living their best mutable life.",
6601
+ "method_missing: the Ruby equivalent of 'I'll figure it out at runtime.'",
6602
+ "This class reopens three other classes. Ruby allows it. That doesn't mean you should.",
6603
+ "Monkey-patching String in 2026: bold, chaotic, deeply personal."
6405
6604
  ];
6406
6605
  var phpRoasts = [
6407
6606
  "PHP: where SQL injection goes to be born.",
6408
6607
  "This code predates prepared statements. And dignity.",
6409
6608
  "MD5 for passwords in 2026. Bold choice.",
6410
- "var_dump() in production: the poor man's observability platform."
6609
+ "var_dump() in production: the poor man's observability platform.",
6610
+ "Little Bobby Tables has a summer home in your database thanks to this query.",
6611
+ "MD5 passwords: cracked before the response even reaches the client.",
6612
+ "var_dump() in a prod endpoint: your users are now debugging with you, whether they want to or not.",
6613
+ "This PHP predates PSR standards. It predates several PHP versions. It predates regret."
6411
6614
  ];
6412
6615
  var swiftRoasts = [
6413
6616
  "Force unwrapping: Swift's way of saying 'I believe in you... mostly'.",
6414
6617
  "This SwiftUI view has more @State than a government agency.",
6415
6618
  "print() for debugging in production. Classic.",
6416
- "Callback pyramid: the Great Pyramid of Giza, but for closures."
6619
+ "Callback pyramid: the Great Pyramid of Giza, but for closures.",
6620
+ "Force unwrap on user data: a crash report waiting to be filed.",
6621
+ "This view has so much @State it should file for statehood.",
6622
+ "The callback pyramid is so deep it has base camp and a summit team.",
6623
+ "print() in production: your logs are now Xcode console screenshots."
6417
6624
  ];
6418
6625
  var kotlinRoasts = [
6419
6626
  "!! in Kotlin: because NullPointerExceptions were getting lonely.",
6420
6627
  "GlobalScope: structured concurrency's nemesis.",
6421
6628
  "runBlocking in a coroutine. Thread blocked. Dreams crushed.",
6422
- "println() for logging: Kotlin 101, lesson 0."
6629
+ "println() for logging: Kotlin 101, lesson 0.",
6630
+ "!! operator: Kotlin tried to protect you from null. You said no thanks.",
6631
+ "GlobalScope.launch: fire, forget, and crash mysteriously three hours later.",
6632
+ "runBlocking inside a coroutine: the deadlock is theoretical until it isn't.",
6633
+ "println() in production Kotlin: the Android logcat is right there."
6423
6634
  ];
6424
6635
  var testQualityRoasts = [
6425
6636
  "Tests that always pass are basically just green noise.",
6426
6637
  "expect(true).toBe(true): peak TDD.",
6427
6638
  "Skipped tests: the software equivalent of 'we'll fix it in post'.",
6428
6639
  ".only in CI: one test to rule them all, one test to find them, one test to bring the pipeline down.",
6429
- "No assertions? You're not testing, you're just running code for fun."
6640
+ "No assertions? You're not testing, you're just running code for fun.",
6641
+ "expect(true).toBe(true) \u2014 a test that tests the concept of testing, nothing else.",
6642
+ "test.skip: the CI pipeline is green. The problem is not solved. These are different things.",
6643
+ "This test has no assertions. It passes every time. It tests nothing. Green checkmark. \u{1F921}",
6644
+ "describe('everything', () => it('works', () => {})) \u2014 the test suite as performance art."
6430
6645
  ];
6431
6646
  var databaseRoasts = [
6432
6647
  "N+1 queries: the ORM's way of testing your database's patience.",
@@ -6434,27 +6649,43 @@ var databaseRoasts = [
6434
6649
  "Raw SQL in an ORM project. Why have an ORM at all?",
6435
6650
  "sync({ force: true }) in production. Bold strategy. Let's see how it pays off.",
6436
6651
  "No indexes. Your database is doing a full table scan and judging you.",
6437
- "Hardcoded database credentials. Committing to the problem, one git push at a time."
6652
+ "Hardcoded database credentials. Committing to the problem, one git push at a time.",
6653
+ "N+1 queries: you asked for one thing and got a DDoS of your own making.",
6654
+ "SELECT * FROM users \u2014 your DBA is already writing their resignation.",
6655
+ "sync({ force: true }) in production drops all tables. This is not a simulation.",
6656
+ "No indexes on a 10M row table. The query planner has left the building.",
6657
+ "findAll() with no limit: pagination exists. Use it before the table does."
6438
6658
  ];
6439
6659
  var configAuditRoasts = [
6440
6660
  "strict: false in tsconfig. Living life on the edge.",
6441
6661
  "No ESLint config. The lint-free lifestyle has consequences.",
6442
6662
  "TypeScript without strict mode is just JavaScript with extra keystrokes.",
6443
6663
  "skipLibCheck: true \u2014 because type errors in your dependencies are someone else's problem.",
6444
- "No Prettier config. Every file has its own formatting style. Delightful."
6664
+ "No Prettier config. Every file has its own formatting style. Delightful.",
6665
+ "strict: false \u2014 TypeScript is now suggestions-only. Congrats on your JavaScript.",
6666
+ "No ESLint: every PR is a negotiation over style instead of correctness.",
6667
+ "skipLibCheck: true is the 'not my problem' of TypeScript configuration.",
6668
+ "No Prettier config: tabs vs spaces, decided per-file, per-dev, per-mood."
6445
6669
  ];
6446
6670
  var bundleSizeRoasts = [
6447
6671
  "Your bundle grew 50%. Hope your users enjoy buffering.",
6448
6672
  "This bundle is so big it needs its own loading screen.",
6449
6673
  "Bundle size regression detected. Time to blame that one npm install.",
6450
- "Your JavaScript bundle is now larger than some operating systems."
6674
+ "Your JavaScript bundle is now larger than some operating systems.",
6675
+ "Users on 4G have filed a complaint.",
6676
+ "The bundle is so large it arrives before the HTML but after the user left.",
6677
+ "Webpack looked at your imports and cried.",
6678
+ "This bundle ships more JS than the Apollo 11 guidance computer had total memory. Reflect on that."
6451
6679
  ];
6452
6680
  var licenseRoasts = [
6453
6681
  "GPL in your dependency tree: open source whether you like it or not.",
6454
6682
  "AGPL: the license that says 'if you use this, you owe the world your code'.",
6455
6683
  "Unknown license: Schr\xF6dinger's compliance \u2014 you don't know until a lawyer opens the box.",
6456
6684
  "LGPL: the polite version of 'we're watching you'.",
6457
- "Mixing GPL with proprietary code. Legal's going to love this conversation."
6685
+ "Mixing GPL with proprietary code. Legal's going to love this conversation.",
6686
+ "Unknown license: Schr\xF6dinger's lawsuit \u2014 compliance is both violated and fine until legal observes it.",
6687
+ "AGPL in a SaaS dependency: your lawyers are going to need a moment.",
6688
+ "GPL inheritance: it's not just a license, it's a lifestyle your whole codebase now shares."
6458
6689
  ];
6459
6690
  var comboRoasts = [
6460
6691
  "Multiple critical systems are asking for attention simultaneously. Triage recommended.",
@@ -6468,7 +6699,14 @@ var comboRoasts = [
6468
6699
  "This is a target-rich environment.",
6469
6700
  "Broad problems suggest systemic causes, not isolated mistakes.",
6470
6701
  "The findings span architecture, style, security, and testing. A full house.",
6471
- "This codebase is doing a lot of things. Unfortunately, several of them are wrong."
6702
+ "This codebase is doing a lot of things. Unfortunately, several of them are wrong.",
6703
+ // meme refs
6704
+ "The issues said 'we're not so different, you and I' and they were right.",
6705
+ "This is fine. \u{1F525} (Narrator: it was not fine.)",
6706
+ "Every category lit up. It's giving Christmas tree, but make it a production incident.",
6707
+ "The findings didn't just multiply \u2014 they organised.",
6708
+ "We found problems in places we weren't even looking. Bonus content.",
6709
+ "Bro's codebase said 'why have one problem when you can have them all.'"
6472
6710
  ];
6473
6711
  var prSizeRoasts = [
6474
6712
  "A PR this large is not a feature. It's a chapter.",
@@ -6478,7 +6716,13 @@ var prSizeRoasts = [
6478
6716
  "This PR changed enough files that 'looks good to me' is technically true but meaningless.",
6479
6717
  "The git diff for this PR has its own table of contents.",
6480
6718
  "Shipping a PR this size is optimistic. Reviewing it is fiction.",
6481
- "A 40-file PR is not a feature. It's a hostage situation."
6719
+ "A 40-file PR is not a feature. It's a hostage situation.",
6720
+ // meme refs
6721
+ "LGTM \u{1F44D} (did not read)",
6722
+ "This PR is so large the reviewer approved it out of self-preservation.",
6723
+ "One PR, 47 files, zero reviewers who finished reading it.",
6724
+ "PR so big it should have been a branch, a milestone, and a retrospective.",
6725
+ "The diff is longer than the feature spec. That's a flag."
6482
6726
  ];
6483
6727
  function pick(arr) {
6484
6728
  return arr[Math.floor(Math.random() * arr.length)];
@@ -8733,6 +8977,34 @@ function renderReport(report, options) {
8733
8977
  ` ${chalk4.cyan("Dev Dependencies")} ${report.stats.devDependencies}`
8734
8978
  );
8735
8979
  sections.push("");
8980
+ const FINDING_TO_ROAST_CATEGORY = {
8981
+ "unused-deps": "dependencies",
8982
+ "nextjs-metadata": "framework",
8983
+ "nextjs-client-server": "framework",
8984
+ "react-error-boundary": "framework",
8985
+ "secrets": "security",
8986
+ "env-in-git": "security",
8987
+ "eval-usage": "security",
8988
+ "npm-audit": "npm-audit",
8989
+ "dep-outdated": "dep-outdated",
8990
+ "ruby-style": "ruby-issues",
8991
+ "php-smell": "php-issues",
8992
+ "swift-async": "swift-issues",
8993
+ "kotlin-coroutine": "kotlin-issues",
8994
+ "db-n-plus-one": "database",
8995
+ "db-sql-injection": "database",
8996
+ "db-over-fetch": "database",
8997
+ "db-destructive": "database"
8998
+ };
8999
+ const roastByFile = /* @__PURE__ */ new Map();
9000
+ const roastByCategory = /* @__PURE__ */ new Map();
9001
+ for (const roast of report.roasts) {
9002
+ if (roast.target === "codebase") continue;
9003
+ roastByCategory.set(roast.category, roast.message);
9004
+ if (roast.target.includes("/") || roast.target.includes(".") && !roast.target.includes(" ")) {
9005
+ roastByFile.set(roast.target, roast.message);
9006
+ }
9007
+ }
8736
9008
  const warnings = report.findings.filter((f) => f.severity === "warning");
8737
9009
  const criticals = report.findings.filter((f) => f.severity === "critical");
8738
9010
  const infos = report.findings.filter((f) => f.severity === "info");
@@ -8753,27 +9025,37 @@ function renderReport(report, options) {
8753
9025
  sections.push(` ${chalk4.blue("\u25CF")} ${chalk4.blue(`${infos.length} info`)}`);
8754
9026
  }
8755
9027
  sections.push("");
9028
+ const shownRoastKeys = /* @__PURE__ */ new Set();
8756
9029
  const keyFindings = [...criticals, ...warnings].slice(0, 8);
8757
9030
  for (const finding of keyFindings) {
8758
9031
  const icon = finding.severity === "critical" ? chalk4.red("\u2717") : chalk4.yellow("\u26A0");
8759
9032
  sections.push(` ${icon} ${chalk4.white(finding.message)}`);
9033
+ let roastMsg;
9034
+ let roastKey;
9035
+ if (finding.file && roastByFile.has(finding.file)) {
9036
+ roastKey = `file:${finding.file}`;
9037
+ if (!shownRoastKeys.has(roastKey)) {
9038
+ roastMsg = roastByFile.get(finding.file);
9039
+ }
9040
+ }
9041
+ if (!roastMsg) {
9042
+ const resolvedCategory = FINDING_TO_ROAST_CATEGORY[finding.category] ?? finding.category;
9043
+ roastKey = `cat:${resolvedCategory}`;
9044
+ if (!shownRoastKeys.has(roastKey)) {
9045
+ roastMsg = roastByCategory.get(resolvedCategory);
9046
+ }
9047
+ }
9048
+ if (roastMsg && roastKey) {
9049
+ sections.push(` ${chalk4.italic.dim(roastMsg)}`);
9050
+ shownRoastKeys.add(roastKey);
9051
+ }
8760
9052
  }
8761
9053
  sections.push("");
8762
9054
  }
8763
- if (report.roasts.length > 0) {
8764
- sections.push(
8765
- boxen(chalk4.bold.yellow(" Roast Time ") + " " + flame(), {
8766
- padding: { top: 0, bottom: 0, left: 1, right: 1 },
8767
- borderStyle: "round",
8768
- borderColor: "yellow"
8769
- })
8770
- );
9055
+ const comboRoast = report.roasts.find((r) => r.target === "codebase");
9056
+ if (comboRoast) {
9057
+ sections.push(chalk4.italic.yellow(` ${comboRoast.message}`));
8771
9058
  sections.push("");
8772
- for (const roast of report.roasts) {
8773
- sections.push(` ${chalk4.bold.white(roast.target)}`);
8774
- sections.push(` ${chalk4.yellow(roast.message)}`);
8775
- sections.push("");
8776
- }
8777
9059
  }
8778
9060
  if (report.fixes && report.fixes.length > 0) {
8779
9061
  sections.push(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roast-my-codebase",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Get roasted. Get better. Ship faster. A CLI that analyzes your codebase and delivers brutally honest (but funny) feedback.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",