@booklib/core 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/.cursor/rules/booklib-standards.mdc +40 -0
  2. package/.gemini/context.md +372 -0
  3. package/AGENTS.md +166 -0
  4. package/CHANGELOG.md +226 -0
  5. package/CLAUDE.md +81 -0
  6. package/CODE_OF_CONDUCT.md +31 -0
  7. package/CONTRIBUTING.md +304 -0
  8. package/LICENSE +21 -0
  9. package/PLAN.md +28 -0
  10. package/README.ja.md +198 -0
  11. package/README.ko.md +198 -0
  12. package/README.md +503 -0
  13. package/README.pt-BR.md +198 -0
  14. package/README.uk.md +241 -0
  15. package/README.zh-CN.md +198 -0
  16. package/SECURITY.md +9 -0
  17. package/agents/architecture-reviewer.md +136 -0
  18. package/agents/booklib-reviewer.md +90 -0
  19. package/agents/data-reviewer.md +107 -0
  20. package/agents/jvm-reviewer.md +146 -0
  21. package/agents/python-reviewer.md +128 -0
  22. package/agents/rust-reviewer.md +115 -0
  23. package/agents/ts-reviewer.md +110 -0
  24. package/agents/ui-reviewer.md +117 -0
  25. package/assets/logo.svg +36 -0
  26. package/bin/booklib-mcp.js +304 -0
  27. package/bin/booklib.js +1705 -0
  28. package/bin/skills.cjs +1292 -0
  29. package/booklib-router.mdc +36 -0
  30. package/booklib.config.json +19 -0
  31. package/commands/animation-at-work.md +10 -0
  32. package/commands/clean-code-reviewer.md +10 -0
  33. package/commands/data-intensive-patterns.md +10 -0
  34. package/commands/data-pipelines.md +10 -0
  35. package/commands/design-patterns.md +10 -0
  36. package/commands/domain-driven-design.md +10 -0
  37. package/commands/effective-java.md +10 -0
  38. package/commands/effective-kotlin.md +10 -0
  39. package/commands/effective-python.md +10 -0
  40. package/commands/effective-typescript.md +10 -0
  41. package/commands/kotlin-in-action.md +10 -0
  42. package/commands/lean-startup.md +10 -0
  43. package/commands/microservices-patterns.md +10 -0
  44. package/commands/programming-with-rust.md +10 -0
  45. package/commands/refactoring-ui.md +10 -0
  46. package/commands/rust-in-action.md +10 -0
  47. package/commands/skill-router.md +10 -0
  48. package/commands/spring-boot-in-action.md +10 -0
  49. package/commands/storytelling-with-data.md +10 -0
  50. package/commands/system-design-interview.md +10 -0
  51. package/commands/using-asyncio-python.md +10 -0
  52. package/commands/web-scraping-python.md +10 -0
  53. package/community/registry.json +1616 -0
  54. package/hooks/hooks.json +23 -0
  55. package/hooks/posttooluse-capture.mjs +67 -0
  56. package/hooks/suggest.js +153 -0
  57. package/lib/agent-behaviors.js +40 -0
  58. package/lib/agent-detector.js +96 -0
  59. package/lib/config-loader.js +39 -0
  60. package/lib/conflict-resolver.js +148 -0
  61. package/lib/context-builder.js +574 -0
  62. package/lib/discovery-engine.js +298 -0
  63. package/lib/doctor/hook-installer.js +83 -0
  64. package/lib/doctor/usage-tracker.js +87 -0
  65. package/lib/engine/ai-features.js +253 -0
  66. package/lib/engine/auditor.js +103 -0
  67. package/lib/engine/bm25-index.js +178 -0
  68. package/lib/engine/capture.js +120 -0
  69. package/lib/engine/corrections.js +198 -0
  70. package/lib/engine/doctor.js +195 -0
  71. package/lib/engine/graph-injector.js +137 -0
  72. package/lib/engine/graph.js +161 -0
  73. package/lib/engine/handoff.js +405 -0
  74. package/lib/engine/indexer.js +242 -0
  75. package/lib/engine/parser.js +53 -0
  76. package/lib/engine/query-expander.js +42 -0
  77. package/lib/engine/reranker.js +40 -0
  78. package/lib/engine/rrf.js +59 -0
  79. package/lib/engine/scanner.js +151 -0
  80. package/lib/engine/searcher.js +139 -0
  81. package/lib/engine/session-coordinator.js +306 -0
  82. package/lib/engine/session-manager.js +429 -0
  83. package/lib/engine/synthesizer.js +70 -0
  84. package/lib/installer.js +70 -0
  85. package/lib/instinct-block.js +33 -0
  86. package/lib/mcp-config-writer.js +88 -0
  87. package/lib/paths.js +57 -0
  88. package/lib/profiles/design.md +19 -0
  89. package/lib/profiles/general.md +16 -0
  90. package/lib/profiles/research-analysis.md +22 -0
  91. package/lib/profiles/software-development.md +23 -0
  92. package/lib/profiles/writing-content.md +19 -0
  93. package/lib/project-initializer.js +916 -0
  94. package/lib/registry/skills.js +102 -0
  95. package/lib/registry-searcher.js +99 -0
  96. package/lib/rules/rules-manager.js +169 -0
  97. package/lib/skill-fetcher.js +333 -0
  98. package/lib/well-known-builder.js +70 -0
  99. package/lib/wizard/index.js +404 -0
  100. package/lib/wizard/integration-detector.js +41 -0
  101. package/lib/wizard/project-detector.js +100 -0
  102. package/lib/wizard/prompt.js +156 -0
  103. package/lib/wizard/registry-embeddings.js +107 -0
  104. package/lib/wizard/skill-recommender.js +69 -0
  105. package/llms-full.txt +254 -0
  106. package/llms.txt +70 -0
  107. package/package.json +45 -0
  108. package/research-reports/2026-04-01-current-architecture.md +160 -0
  109. package/research-reports/IDEAS.md +93 -0
  110. package/rules/common/clean-code.md +42 -0
  111. package/rules/java/effective-java.md +42 -0
  112. package/rules/kotlin/effective-kotlin.md +37 -0
  113. package/rules/python/effective-python.md +38 -0
  114. package/rules/rust/rust.md +37 -0
  115. package/rules/typescript/effective-typescript.md +42 -0
  116. package/scripts/gen-llms-full.mjs +36 -0
  117. package/scripts/gen-og.mjs +142 -0
  118. package/scripts/validate-frontmatter.js +25 -0
  119. package/skills/animation-at-work/SKILL.md +270 -0
  120. package/skills/animation-at-work/assets/example_asset.txt +1 -0
  121. package/skills/animation-at-work/evals/evals.json +44 -0
  122. package/skills/animation-at-work/evals/results.json +13 -0
  123. package/skills/animation-at-work/examples/after.md +64 -0
  124. package/skills/animation-at-work/examples/before.md +35 -0
  125. package/skills/animation-at-work/references/api_reference.md +369 -0
  126. package/skills/animation-at-work/references/review-checklist.md +79 -0
  127. package/skills/animation-at-work/scripts/audit_animations.py +295 -0
  128. package/skills/animation-at-work/scripts/example.py +1 -0
  129. package/skills/clean-code-reviewer/SKILL.md +444 -0
  130. package/skills/clean-code-reviewer/audit.json +35 -0
  131. package/skills/clean-code-reviewer/evals/evals.json +185 -0
  132. package/skills/clean-code-reviewer/evals/results.json +13 -0
  133. package/skills/clean-code-reviewer/examples/after.md +48 -0
  134. package/skills/clean-code-reviewer/examples/before.md +33 -0
  135. package/skills/clean-code-reviewer/references/api_reference.md +158 -0
  136. package/skills/clean-code-reviewer/references/practices-catalog.md +282 -0
  137. package/skills/clean-code-reviewer/references/review-checklist.md +254 -0
  138. package/skills/clean-code-reviewer/scripts/pre-review.py +206 -0
  139. package/skills/data-intensive-patterns/SKILL.md +267 -0
  140. package/skills/data-intensive-patterns/assets/example_asset.txt +1 -0
  141. package/skills/data-intensive-patterns/evals/evals.json +54 -0
  142. package/skills/data-intensive-patterns/evals/results.json +13 -0
  143. package/skills/data-intensive-patterns/examples/after.md +61 -0
  144. package/skills/data-intensive-patterns/examples/before.md +38 -0
  145. package/skills/data-intensive-patterns/references/api_reference.md +34 -0
  146. package/skills/data-intensive-patterns/references/patterns-catalog.md +551 -0
  147. package/skills/data-intensive-patterns/references/review-checklist.md +193 -0
  148. package/skills/data-intensive-patterns/scripts/adr.py +213 -0
  149. package/skills/data-intensive-patterns/scripts/example.py +1 -0
  150. package/skills/data-pipelines/SKILL.md +259 -0
  151. package/skills/data-pipelines/assets/example_asset.txt +1 -0
  152. package/skills/data-pipelines/evals/evals.json +45 -0
  153. package/skills/data-pipelines/evals/results.json +13 -0
  154. package/skills/data-pipelines/examples/after.md +97 -0
  155. package/skills/data-pipelines/examples/before.md +37 -0
  156. package/skills/data-pipelines/references/api_reference.md +301 -0
  157. package/skills/data-pipelines/references/review-checklist.md +181 -0
  158. package/skills/data-pipelines/scripts/example.py +1 -0
  159. package/skills/data-pipelines/scripts/new_pipeline.py +444 -0
  160. package/skills/design-patterns/SKILL.md +271 -0
  161. package/skills/design-patterns/assets/example_asset.txt +1 -0
  162. package/skills/design-patterns/evals/evals.json +46 -0
  163. package/skills/design-patterns/evals/results.json +13 -0
  164. package/skills/design-patterns/examples/after.md +52 -0
  165. package/skills/design-patterns/examples/before.md +29 -0
  166. package/skills/design-patterns/references/api_reference.md +1 -0
  167. package/skills/design-patterns/references/patterns-catalog.md +726 -0
  168. package/skills/design-patterns/references/review-checklist.md +173 -0
  169. package/skills/design-patterns/scripts/example.py +1 -0
  170. package/skills/design-patterns/scripts/scaffold.py +807 -0
  171. package/skills/domain-driven-design/SKILL.md +142 -0
  172. package/skills/domain-driven-design/assets/example_asset.txt +1 -0
  173. package/skills/domain-driven-design/evals/evals.json +48 -0
  174. package/skills/domain-driven-design/evals/results.json +13 -0
  175. package/skills/domain-driven-design/examples/after.md +80 -0
  176. package/skills/domain-driven-design/examples/before.md +43 -0
  177. package/skills/domain-driven-design/references/api_reference.md +1 -0
  178. package/skills/domain-driven-design/references/patterns-catalog.md +545 -0
  179. package/skills/domain-driven-design/references/review-checklist.md +158 -0
  180. package/skills/domain-driven-design/scripts/example.py +1 -0
  181. package/skills/domain-driven-design/scripts/scaffold.py +421 -0
  182. package/skills/effective-java/SKILL.md +227 -0
  183. package/skills/effective-java/assets/example_asset.txt +1 -0
  184. package/skills/effective-java/evals/evals.json +46 -0
  185. package/skills/effective-java/evals/results.json +13 -0
  186. package/skills/effective-java/examples/after.md +83 -0
  187. package/skills/effective-java/examples/before.md +37 -0
  188. package/skills/effective-java/references/api_reference.md +1 -0
  189. package/skills/effective-java/references/items-catalog.md +955 -0
  190. package/skills/effective-java/references/review-checklist.md +216 -0
  191. package/skills/effective-java/scripts/checkstyle_setup.py +211 -0
  192. package/skills/effective-java/scripts/example.py +1 -0
  193. package/skills/effective-kotlin/SKILL.md +271 -0
  194. package/skills/effective-kotlin/assets/example_asset.txt +1 -0
  195. package/skills/effective-kotlin/audit.json +29 -0
  196. package/skills/effective-kotlin/evals/evals.json +45 -0
  197. package/skills/effective-kotlin/evals/results.json +13 -0
  198. package/skills/effective-kotlin/examples/after.md +36 -0
  199. package/skills/effective-kotlin/examples/before.md +38 -0
  200. package/skills/effective-kotlin/references/api_reference.md +1 -0
  201. package/skills/effective-kotlin/references/practices-catalog.md +1228 -0
  202. package/skills/effective-kotlin/references/review-checklist.md +126 -0
  203. package/skills/effective-kotlin/scripts/example.py +1 -0
  204. package/skills/effective-python/SKILL.md +441 -0
  205. package/skills/effective-python/evals/evals.json +44 -0
  206. package/skills/effective-python/evals/results.json +13 -0
  207. package/skills/effective-python/examples/after.md +56 -0
  208. package/skills/effective-python/examples/before.md +40 -0
  209. package/skills/effective-python/ref-01-pythonic-thinking.md +202 -0
  210. package/skills/effective-python/ref-02-lists-and-dicts.md +146 -0
  211. package/skills/effective-python/ref-03-functions.md +186 -0
  212. package/skills/effective-python/ref-04-comprehensions-generators.md +211 -0
  213. package/skills/effective-python/ref-05-classes-interfaces.md +188 -0
  214. package/skills/effective-python/ref-06-metaclasses-attributes.md +209 -0
  215. package/skills/effective-python/ref-07-concurrency.md +213 -0
  216. package/skills/effective-python/ref-08-robustness-performance.md +248 -0
  217. package/skills/effective-python/ref-09-testing-debugging.md +253 -0
  218. package/skills/effective-python/ref-10-collaboration.md +175 -0
  219. package/skills/effective-python/references/api_reference.md +218 -0
  220. package/skills/effective-python/references/practices-catalog.md +483 -0
  221. package/skills/effective-python/references/review-checklist.md +190 -0
  222. package/skills/effective-python/scripts/lint.py +173 -0
  223. package/skills/effective-typescript/SKILL.md +262 -0
  224. package/skills/effective-typescript/audit.json +29 -0
  225. package/skills/effective-typescript/evals/evals.json +37 -0
  226. package/skills/effective-typescript/evals/results.json +13 -0
  227. package/skills/effective-typescript/examples/after.md +70 -0
  228. package/skills/effective-typescript/examples/before.md +47 -0
  229. package/skills/effective-typescript/references/api_reference.md +118 -0
  230. package/skills/effective-typescript/references/practices-catalog.md +371 -0
  231. package/skills/effective-typescript/scripts/review.py +169 -0
  232. package/skills/kotlin-in-action/SKILL.md +261 -0
  233. package/skills/kotlin-in-action/assets/example_asset.txt +1 -0
  234. package/skills/kotlin-in-action/evals/evals.json +43 -0
  235. package/skills/kotlin-in-action/evals/results.json +13 -0
  236. package/skills/kotlin-in-action/examples/after.md +53 -0
  237. package/skills/kotlin-in-action/examples/before.md +39 -0
  238. package/skills/kotlin-in-action/references/api_reference.md +1 -0
  239. package/skills/kotlin-in-action/references/practices-catalog.md +436 -0
  240. package/skills/kotlin-in-action/references/review-checklist.md +204 -0
  241. package/skills/kotlin-in-action/scripts/example.py +1 -0
  242. package/skills/kotlin-in-action/scripts/setup_detekt.py +224 -0
  243. package/skills/lean-startup/SKILL.md +160 -0
  244. package/skills/lean-startup/assets/example_asset.txt +1 -0
  245. package/skills/lean-startup/evals/evals.json +43 -0
  246. package/skills/lean-startup/evals/results.json +13 -0
  247. package/skills/lean-startup/examples/after.md +80 -0
  248. package/skills/lean-startup/examples/before.md +34 -0
  249. package/skills/lean-startup/references/api_reference.md +319 -0
  250. package/skills/lean-startup/references/review-checklist.md +137 -0
  251. package/skills/lean-startup/scripts/example.py +1 -0
  252. package/skills/lean-startup/scripts/new_experiment.py +286 -0
  253. package/skills/microservices-patterns/SKILL.md +384 -0
  254. package/skills/microservices-patterns/evals/evals.json +45 -0
  255. package/skills/microservices-patterns/evals/results.json +13 -0
  256. package/skills/microservices-patterns/examples/after.md +69 -0
  257. package/skills/microservices-patterns/examples/before.md +40 -0
  258. package/skills/microservices-patterns/references/patterns-catalog.md +391 -0
  259. package/skills/microservices-patterns/references/review-checklist.md +169 -0
  260. package/skills/microservices-patterns/scripts/new_service.py +583 -0
  261. package/skills/programming-with-rust/SKILL.md +209 -0
  262. package/skills/programming-with-rust/evals/evals.json +37 -0
  263. package/skills/programming-with-rust/evals/results.json +13 -0
  264. package/skills/programming-with-rust/examples/after.md +107 -0
  265. package/skills/programming-with-rust/examples/before.md +59 -0
  266. package/skills/programming-with-rust/references/api_reference.md +152 -0
  267. package/skills/programming-with-rust/references/practices-catalog.md +335 -0
  268. package/skills/programming-with-rust/scripts/review.py +142 -0
  269. package/skills/refactoring-ui/SKILL.md +362 -0
  270. package/skills/refactoring-ui/assets/example_asset.txt +1 -0
  271. package/skills/refactoring-ui/evals/evals.json +45 -0
  272. package/skills/refactoring-ui/evals/results.json +13 -0
  273. package/skills/refactoring-ui/examples/after.md +85 -0
  274. package/skills/refactoring-ui/examples/before.md +58 -0
  275. package/skills/refactoring-ui/references/api_reference.md +355 -0
  276. package/skills/refactoring-ui/references/review-checklist.md +114 -0
  277. package/skills/refactoring-ui/scripts/audit_css.py +250 -0
  278. package/skills/refactoring-ui/scripts/example.py +1 -0
  279. package/skills/rust-in-action/SKILL.md +350 -0
  280. package/skills/rust-in-action/evals/evals.json +38 -0
  281. package/skills/rust-in-action/evals/results.json +13 -0
  282. package/skills/rust-in-action/examples/after.md +156 -0
  283. package/skills/rust-in-action/examples/before.md +56 -0
  284. package/skills/rust-in-action/references/practices-catalog.md +346 -0
  285. package/skills/rust-in-action/scripts/review.py +147 -0
  286. package/skills/skill-router/SKILL.md +186 -0
  287. package/skills/skill-router/evals/evals.json +38 -0
  288. package/skills/skill-router/evals/results.json +13 -0
  289. package/skills/skill-router/examples/after.md +63 -0
  290. package/skills/skill-router/examples/before.md +39 -0
  291. package/skills/skill-router/references/api_reference.md +24 -0
  292. package/skills/skill-router/references/routing-heuristics.md +89 -0
  293. package/skills/skill-router/references/skill-catalog.md +174 -0
  294. package/skills/skill-router/scripts/route.py +266 -0
  295. package/skills/spring-boot-in-action/SKILL.md +340 -0
  296. package/skills/spring-boot-in-action/evals/evals.json +39 -0
  297. package/skills/spring-boot-in-action/evals/results.json +13 -0
  298. package/skills/spring-boot-in-action/examples/after.md +185 -0
  299. package/skills/spring-boot-in-action/examples/before.md +84 -0
  300. package/skills/spring-boot-in-action/references/practices-catalog.md +403 -0
  301. package/skills/spring-boot-in-action/scripts/review.py +184 -0
  302. package/skills/storytelling-with-data/SKILL.md +241 -0
  303. package/skills/storytelling-with-data/assets/example_asset.txt +1 -0
  304. package/skills/storytelling-with-data/evals/evals.json +47 -0
  305. package/skills/storytelling-with-data/evals/results.json +13 -0
  306. package/skills/storytelling-with-data/examples/after.md +50 -0
  307. package/skills/storytelling-with-data/examples/before.md +33 -0
  308. package/skills/storytelling-with-data/references/api_reference.md +379 -0
  309. package/skills/storytelling-with-data/references/review-checklist.md +111 -0
  310. package/skills/storytelling-with-data/scripts/chart_review.py +301 -0
  311. package/skills/storytelling-with-data/scripts/example.py +1 -0
  312. package/skills/system-design-interview/SKILL.md +233 -0
  313. package/skills/system-design-interview/assets/example_asset.txt +1 -0
  314. package/skills/system-design-interview/evals/evals.json +46 -0
  315. package/skills/system-design-interview/evals/results.json +13 -0
  316. package/skills/system-design-interview/examples/after.md +94 -0
  317. package/skills/system-design-interview/examples/before.md +27 -0
  318. package/skills/system-design-interview/references/api_reference.md +582 -0
  319. package/skills/system-design-interview/references/review-checklist.md +201 -0
  320. package/skills/system-design-interview/scripts/example.py +1 -0
  321. package/skills/system-design-interview/scripts/new_design.py +421 -0
  322. package/skills/using-asyncio-python/SKILL.md +290 -0
  323. package/skills/using-asyncio-python/assets/example_asset.txt +1 -0
  324. package/skills/using-asyncio-python/evals/evals.json +43 -0
  325. package/skills/using-asyncio-python/evals/results.json +13 -0
  326. package/skills/using-asyncio-python/examples/after.md +68 -0
  327. package/skills/using-asyncio-python/examples/before.md +39 -0
  328. package/skills/using-asyncio-python/references/api_reference.md +267 -0
  329. package/skills/using-asyncio-python/references/review-checklist.md +149 -0
  330. package/skills/using-asyncio-python/scripts/check_blocking.py +270 -0
  331. package/skills/using-asyncio-python/scripts/example.py +1 -0
  332. package/skills/web-scraping-python/SKILL.md +280 -0
  333. package/skills/web-scraping-python/assets/example_asset.txt +1 -0
  334. package/skills/web-scraping-python/evals/evals.json +46 -0
  335. package/skills/web-scraping-python/evals/results.json +13 -0
  336. package/skills/web-scraping-python/examples/after.md +109 -0
  337. package/skills/web-scraping-python/examples/before.md +40 -0
  338. package/skills/web-scraping-python/references/api_reference.md +393 -0
  339. package/skills/web-scraping-python/references/review-checklist.md +163 -0
  340. package/skills/web-scraping-python/scripts/example.py +1 -0
  341. package/skills/web-scraping-python/scripts/new_scraper.py +231 -0
  342. package/skills/writing-plans/audit.json +34 -0
  343. package/tests/agent-detector.test.js +83 -0
  344. package/tests/corrections.test.js +245 -0
  345. package/tests/doctor/hook-installer.test.js +72 -0
  346. package/tests/doctor/usage-tracker.test.js +140 -0
  347. package/tests/engine/benchmark-eval.test.js +31 -0
  348. package/tests/engine/bm25-index.test.js +85 -0
  349. package/tests/engine/capture-command.test.js +35 -0
  350. package/tests/engine/capture.test.js +17 -0
  351. package/tests/engine/graph-augmented-search.test.js +107 -0
  352. package/tests/engine/graph-injector.test.js +44 -0
  353. package/tests/engine/graph.test.js +216 -0
  354. package/tests/engine/hybrid-searcher.test.js +74 -0
  355. package/tests/engine/indexer-bm25.test.js +37 -0
  356. package/tests/engine/mcp-tools.test.js +73 -0
  357. package/tests/engine/project-initializer-mcp.test.js +99 -0
  358. package/tests/engine/query-expander.test.js +36 -0
  359. package/tests/engine/reranker.test.js +51 -0
  360. package/tests/engine/rrf.test.js +49 -0
  361. package/tests/engine/srag-prefix.test.js +47 -0
  362. package/tests/instinct-block.test.js +23 -0
  363. package/tests/mcp-config-writer.test.js +60 -0
  364. package/tests/project-initializer-new-agents.test.js +48 -0
  365. package/tests/rules/rules-manager.test.js +230 -0
  366. package/tests/well-known-builder.test.js +40 -0
  367. package/tests/wizard/integration-detector.test.js +31 -0
  368. package/tests/wizard/project-detector.test.js +51 -0
  369. package/tests/wizard/prompt-session.test.js +61 -0
  370. package/tests/wizard/prompt.test.js +16 -0
  371. package/tests/wizard/registry-embeddings.test.js +35 -0
  372. package/tests/wizard/skill-recommender.test.js +34 -0
  373. package/tests/wizard/slot-count.test.js +25 -0
  374. package/vercel.json +21 -0
@@ -0,0 +1,118 @@
1
+ # Effective TypeScript — All 62 Items
2
+
3
+ All items from Dan Vanderkam's "Effective TypeScript" organized by chapter with priority levels.
4
+
5
+ ## Chapter 1: Getting to Know TypeScript (Items 1–5)
6
+
7
+ | Item | Title | Priority |
8
+ |------|-------|----------|
9
+ | 1 | Understand the Relationship Between TypeScript and JavaScript | Important |
10
+ | 2 | Know Which TypeScript Options You're Using | **Critical** |
11
+ | 3 | Understand That Code Generation Is Independent of Types | Important |
12
+ | 4 | Get Comfortable with Structural Typing | Important |
13
+ | 5 | Limit Use of the `any` Type | **Critical** |
14
+
15
+ ## Chapter 2: TypeScript's Type System (Items 6–18)
16
+
17
+ | Item | Title | Priority |
18
+ |------|-------|----------|
19
+ | 6 | Use Your Editor to Interrogate and Explore the Type System | Suggestion |
20
+ | 7 | Think of Types as Sets of Values | Important |
21
+ | 8 | Know How to Tell Whether a Symbol Is in the Type Space or Value Space | Important |
22
+ | 9 | Prefer Type Declarations to Type Assertions | **Critical** |
23
+ | 10 | Avoid Object Wrapper Types (String, Number, Boolean, Symbol, BigInt) | **Critical** |
24
+ | 11 | Recognize the Limits of Excess Property Checking | Important |
25
+ | 12 | Apply Types to Entire Function Expressions When Possible | Important |
26
+ | 13 | Know the Differences Between `type` and `interface` | Important |
27
+ | 14 | Use Type Operations and Generics to Avoid Repeating Yourself | Important |
28
+ | 15 | Use Index Signatures for Dynamic Data | Important |
29
+ | 16 | Prefer Arrays, Tuples, and ArrayLike to `number` Index Signatures | Suggestion |
30
+ | 17 | Use `readonly` to Avoid Errors Associated with Mutation | Important |
31
+ | 18 | Use Mapped Types to Keep Values in Sync | Important |
32
+
33
+ ## Chapter 3: Type Inference (Items 19–27)
34
+
35
+ | Item | Title | Priority |
36
+ |------|-------|----------|
37
+ | 19 | Avoid Cluttering Your Code with Inferable Types | Suggestion |
38
+ | 20 | Use Different Variables for Different Types | Important |
39
+ | 21 | Understand Type Widening | Important |
40
+ | 22 | Understand Type Narrowing | **Critical** |
41
+ | 23 | Create Objects All at Once | Important |
42
+ | 24 | Be Consistent in Your Use of Aliases | Important |
43
+ | 25 | Use `async` Functions Instead of Callbacks for Asynchronous Code | Important |
44
+ | 26 | Understand How Context Is Used in Type Inference | Important |
45
+ | 27 | Use Functional Constructs and Libraries to Help Types Flow | Suggestion |
46
+
47
+ ## Chapter 4: Type Design (Items 28–37)
48
+
49
+ | Item | Title | Priority |
50
+ |------|-------|----------|
51
+ | 28 | Prefer Types That Always Represent Valid States | **Critical** |
52
+ | 29 | Be Liberal in What You Accept and Strict in What You Produce | Important |
53
+ | 30 | Don't Repeat Type Information in Documentation | Important |
54
+ | 31 | Push Null Values to the Perimeter of Your Types | **Critical** |
55
+ | 32 | Prefer Unions of Interfaces to Interfaces of Unions | **Critical** |
56
+ | 33 | Prefer More Precise Alternatives to String Types | Important |
57
+ | 34 | Prefer Incomplete Types to Inaccurate Types | Important |
58
+ | 35 | Generate Types from APIs and Specs, Not Data | Suggestion |
59
+ | 36 | Name Types Using the Language of Your Problem Domain | Important |
60
+ | 37 | Consider "Brands" for Nominal Typing | Suggestion |
61
+
62
+ ## Chapter 5: Working with any (Items 38–44)
63
+
64
+ | Item | Title | Priority |
65
+ |------|-------|----------|
66
+ | 38 | Use the Narrowest Possible Scope for `any` Types | **Critical** |
67
+ | 39 | Prefer More Precise Variants of `any` to Plain `any` | Important |
68
+ | 40 | Hide Unsafe Type Assertions in Well-Typed Functions | Important |
69
+ | 41 | Understand Evolving `any` | Important |
70
+ | 42 | Use `unknown` Instead of `any` for Values with an Unknown Type | **Critical** |
71
+ | 43 | Prefer Type-Safe Approaches to Monkey Patching | Important |
72
+ | 44 | Track Your Type Coverage to Prevent Regressions in Type Safety | Suggestion |
73
+
74
+ ## Chapter 6: Type Declarations and @types (Items 45–52)
75
+
76
+ | Item | Title | Priority |
77
+ |------|-------|----------|
78
+ | 45 | Put TypeScript and `@types` in devDependencies | Important |
79
+ | 46 | Understand the Three Versions Involved in Type Declarations | Important |
80
+ | 47 | Export All Types That Appear in Public APIs | Important |
81
+ | 48 | Use TSDoc for API Comments | Important |
82
+ | 49 | Provide a Type for `this` in Callbacks | Important |
83
+ | 50 | Prefer Conditional Types to Overloaded Declarations | Suggestion |
84
+ | 51 | Mirror Types to Sever Dependencies | Suggestion |
85
+ | 52 | Be Aware of the Pitfalls of Testing Types | Important |
86
+
87
+ ## Chapter 7: Writing and Running Your Code (Items 53–57)
88
+
89
+ | Item | Title | Priority |
90
+ |------|-------|----------|
91
+ | 53 | Prefer ECMAScript Features to TypeScript Features | Important |
92
+ | 54 | Know How to Iterate Over Objects | Important |
93
+ | 55 | Understand the DOM Hierarchy | Important |
94
+ | 56 | Don't Rely on `private` to Hide Information | Important |
95
+ | 57 | Use Source Maps to Debug TypeScript | Suggestion |
96
+
97
+ ## Chapter 8: Migrating to TypeScript (Items 58–62)
98
+
99
+ | Item | Title | Priority |
100
+ |------|-------|----------|
101
+ | 58 | Write Modern JavaScript | Important |
102
+ | 59 | Use `@ts-check` and JSDoc to Experiment with TypeScript | Suggestion |
103
+ | 60 | Use `allowJs` to Mix TypeScript and JavaScript | Important |
104
+ | 61 | Convert Module by Module Up Your Dependency Graph | Important |
105
+ | 62 | Don't Consider Migration Complete Until You Enable `noImplicitAny` | **Critical** |
106
+
107
+ ---
108
+
109
+ ## Priority Summary
110
+
111
+ **Critical (fix immediately — correctness or safety)**
112
+ Items: 2, 5, 9, 10, 22, 28, 31, 32, 38, 42, 62
113
+
114
+ **Important (fix soon — maintainability and idiom)**
115
+ Items: 3, 4, 7, 8, 11, 12, 13, 14, 15, 17, 18, 20, 21, 23, 24, 25, 26, 29, 30, 33, 34, 36, 39, 40, 41, 43, 45, 46, 47, 48, 49, 52, 53, 54, 55, 56, 58, 60, 61
116
+
117
+ **Suggestion (polish when time allows)**
118
+ Items: 6, 16, 19, 27, 35, 37, 44, 50, 51, 57, 59
@@ -0,0 +1,371 @@
1
+ # Effective TypeScript — Practices Catalog
2
+
3
+ Deep before/after examples for the 20 most impactful items.
4
+
5
+ ---
6
+
7
+ ## Item 2: Know Which TypeScript Options You're Using
8
+
9
+ Always use `strict: true`. It enables `noImplicitAny` and `strictNullChecks` which catch the most common TypeScript bugs.
10
+
11
+ **Before:**
12
+ ```json
13
+ { "compilerOptions": {} }
14
+ ```
15
+ **After:**
16
+ ```json
17
+ { "compilerOptions": { "strict": true, "target": "ES2020", "module": "commonjs" } }
18
+ ```
19
+
20
+ ---
21
+
22
+ ## Item 9: Prefer Type Declarations to Type Assertions
23
+
24
+ **Before:**
25
+ ```typescript
26
+ const user = {} as User; // bypasses type checking — user is actually empty
27
+ const input = document.getElementById('name') as HTMLInputElement;
28
+ ```
29
+ **After:**
30
+ ```typescript
31
+ const user: User = { id: '1', name: 'Alice', email: 'a@example.com' }; // checked
32
+ const input = document.getElementById('name');
33
+ if (input instanceof HTMLInputElement) {
34
+ console.log(input.value); // narrowed, not asserted
35
+ }
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Item 10: Avoid Object Wrapper Types
41
+
42
+ **Before:**
43
+ ```typescript
44
+ function greet(name: String) { // String, not string
45
+ return 'Hello ' + name;
46
+ }
47
+ const s = new String('world');
48
+ greet(s); // works but s !== 'world' as a primitive
49
+ ```
50
+ **After:**
51
+ ```typescript
52
+ function greet(name: string) { // primitive type
53
+ return 'Hello ' + name;
54
+ }
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Item 13: Know the Differences Between `type` and `interface`
60
+
61
+ - Use `interface` for object shapes that consumers may need to extend (open for augmentation)
62
+ - Use `type` for unions, intersections, tuples, and mapped types (cannot be augmented)
63
+
64
+ **Before:**
65
+ ```typescript
66
+ type User = { id: string; name: string }; // fine, but can't be augmented by consumers
67
+ type StringOrNumber = string | number; // correct use of type
68
+ ```
69
+ **After:**
70
+ ```typescript
71
+ interface User { id: string; name: string; } // open for extension
72
+ type StringOrNumber = string | number; // unions must be type aliases
73
+ type ReadonlyUser = Readonly<User>; // mapped type must be type alias
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Item 14: Use Type Operations and Generics to Avoid Repeating Yourself
79
+
80
+ **Before:**
81
+ ```typescript
82
+ interface SavedState { userId: string; name: string; lastSaved: Date; }
83
+ interface UnsavedState { userId: string; name: string; } // repeated fields
84
+ ```
85
+ **After:**
86
+ ```typescript
87
+ interface State { userId: string; name: string; }
88
+ interface SavedState extends State { lastSaved: Date; }
89
+ // Or with Pick/Omit:
90
+ type UnsavedState = Omit<SavedState, 'lastSaved'>;
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Item 17: Use `readonly` to Avoid Errors Associated with Mutation
96
+
97
+ **Before:**
98
+ ```typescript
99
+ function sort(arr: number[]): number[] {
100
+ return arr.sort(); // mutates the original array!
101
+ }
102
+ ```
103
+ **After:**
104
+ ```typescript
105
+ function sort(arr: readonly number[]): number[] {
106
+ return [...arr].sort(); // forced to copy — cannot mutate readonly input
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Item 22: Understand Type Narrowing
113
+
114
+ **Before:**
115
+ ```typescript
116
+ function processInput(val: string | null) {
117
+ console.log(val.toUpperCase()); // error: val is possibly null
118
+ }
119
+ ```
120
+ **After:**
121
+ ```typescript
122
+ function processInput(val: string | null) {
123
+ if (val === null) return;
124
+ console.log(val.toUpperCase()); // narrowed to string
125
+ }
126
+
127
+ // instanceof narrowing
128
+ function format(val: Date | string) {
129
+ if (val instanceof Date) return val.toISOString();
130
+ return val.toUpperCase();
131
+ }
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Item 25: Use async Functions Instead of Callbacks for Asynchronous Code
137
+
138
+ Callbacks produce `any`-typed errors and complex nested types. `async`/`await` lets TypeScript infer `Promise<T>` cleanly.
139
+
140
+ **Before:**
141
+ ```typescript
142
+ function fetchData(url: string, cb: (err: any, data: any) => void) {
143
+ fetch(url)
144
+ .then(r => r.json())
145
+ .then(d => cb(null, d))
146
+ .catch(e => cb(e, null));
147
+ }
148
+ ```
149
+ **After:**
150
+ ```typescript
151
+ async function fetchData<T>(url: string): Promise<T> {
152
+ const response = await fetch(url);
153
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
154
+ return response.json() as T;
155
+ }
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Item 28: Prefer Types That Always Represent Valid States
161
+
162
+ **Before:**
163
+ ```typescript
164
+ interface Page {
165
+ pageText: string;
166
+ isLoading: boolean;
167
+ error: string; // What does isLoading:true + error:'...' mean?
168
+ }
169
+ ```
170
+ **After:**
171
+ ```typescript
172
+ type Page =
173
+ | { state: 'loading' }
174
+ | { state: 'success'; pageText: string }
175
+ | { state: 'error'; error: string };
176
+ // Every combination is meaningful — no impossible states
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Item 31: Push Null Values to the Perimeter
182
+
183
+ **Before:**
184
+ ```typescript
185
+ // null scattered throughout
186
+ function getUser(id: string | null): User | null {
187
+ if (!id) return null;
188
+ const user: User | null = db.find(id) ?? null;
189
+ return user;
190
+ }
191
+ ```
192
+ **After:**
193
+ ```typescript
194
+ // null handled once at the boundary
195
+ function getUser(id: string): User {
196
+ const user = db.find(id);
197
+ if (!user) throw new Error(`User ${id} not found`);
198
+ return user;
199
+ }
200
+ // Callers who might not have an id handle it at their boundary
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Item 32: Prefer Unions of Interfaces to Interfaces of Unions
206
+
207
+ **Before:**
208
+ ```typescript
209
+ interface Layer {
210
+ type: 'fill' | 'line' | 'point';
211
+ fillColor?: string; // only for fill
212
+ lineWidth?: number; // only for line
213
+ pointRadius?: number; // only for point
214
+ // { type: 'fill', lineWidth: 5 } is representable but invalid
215
+ }
216
+ ```
217
+ **After:**
218
+ ```typescript
219
+ interface FillLayer { type: 'fill'; fillColor: string; }
220
+ interface LineLayer { type: 'line'; lineWidth: number; }
221
+ interface PointLayer { type: 'point'; pointRadius: number; }
222
+ type Layer = FillLayer | LineLayer | PointLayer;
223
+ // Each valid state has exactly the right fields
224
+ ```
225
+
226
+ ---
227
+
228
+ ## Item 33: Prefer More Precise Alternatives to String Types
229
+
230
+ **Before:**
231
+ ```typescript
232
+ function setAlignment(align: string) {} // accepts anything
233
+ interface Album { genre: string; } // 'rock', 'jazz', or 'anything'?
234
+ ```
235
+ **After:**
236
+ ```typescript
237
+ type Alignment = 'left' | 'center' | 'right';
238
+ function setAlignment(align: Alignment) {}
239
+
240
+ type Genre = 'rock' | 'jazz' | 'pop' | 'classical';
241
+ interface Album { genre: Genre; }
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Item 38: Use the Narrowest Possible Scope for `any` Types
247
+
248
+ **Before:**
249
+ ```typescript
250
+ const config: any = JSON.parse(rawConfig); // entire variable is any
251
+ console.log(config.timeout); // no type checking from here on
252
+ ```
253
+ **After:**
254
+ ```typescript
255
+ const config = JSON.parse(rawConfig) as { timeout: number; retries: number };
256
+ // or better — parse with unknown and narrow:
257
+ const raw: unknown = JSON.parse(rawConfig);
258
+ const timeout = (raw as { timeout: number }).timeout; // any scoped to one property access
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Item 40: Hide Unsafe Type Assertions in Well-Typed Functions
264
+
265
+ **Before:**
266
+ ```typescript
267
+ // Assertion visible at every call site
268
+ const user = fetchUser() as User;
269
+ ```
270
+ **After:**
271
+ ```typescript
272
+ // Assertion encapsulated once — all callers get proper types
273
+ async function fetchUser(id: string): Promise<User> {
274
+ const raw: unknown = await fetch(`/api/users/${id}`).then(r => r.json());
275
+ return raw as User; // single controlled assertion inside typed boundary
276
+ }
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Item 42: Use `unknown` Instead of `any` for Values with an Unknown Type
282
+
283
+ **Before:**
284
+ ```typescript
285
+ function parseYaml(yaml: string): any { // callers never have to narrow
286
+ return parse(yaml);
287
+ }
288
+ const config = parseYaml(raw);
289
+ config.port.toFixed(); // no error — but crashes if port is missing
290
+ ```
291
+ **After:**
292
+ ```typescript
293
+ function parseYaml(yaml: string): unknown { // callers must narrow before use
294
+ return parse(yaml);
295
+ }
296
+ const config = parseYaml(raw);
297
+ if (typeof config === 'object' && config !== null && 'port' in config) {
298
+ const port = (config as { port: number }).port;
299
+ }
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Item 47: Export All Types That Appear in Public APIs
305
+
306
+ **Before:**
307
+ ```typescript
308
+ // Unexported — users have to use ReturnType<typeof getUser> hacks
309
+ interface User { id: string; name: string; }
310
+ export function getUser(id: string): User { ... }
311
+ ```
312
+ **After:**
313
+ ```typescript
314
+ export interface User { id: string; name: string; } // exported explicitly
315
+ export function getUser(id: string): User { ... }
316
+ ```
317
+
318
+ ---
319
+
320
+ ## Item 48: Use TSDoc for API Comments
321
+
322
+ **Before:**
323
+ ```typescript
324
+ // Fetches user by id. Returns null if not found.
325
+ function getUser(id: string): User | null { ... }
326
+ ```
327
+ **After:**
328
+ ```typescript
329
+ /**
330
+ * Fetches a user by their unique identifier.
331
+ *
332
+ * @param id - The user's unique identifier
333
+ * @returns The user, or null if no user exists with that id
334
+ * @throws {NetworkError} If the network request fails
335
+ */
336
+ function getUser(id: string): User | null { ... }
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Item 53: Prefer ECMAScript Features to TypeScript Features
342
+
343
+ Avoid TypeScript-specific features that don't map cleanly to JavaScript. Prefer standard ES features.
344
+
345
+ **Before:**
346
+ ```typescript
347
+ // TypeScript enums — compiled to objects with side effects, can't be tree-shaken
348
+ enum Direction { North, South, East, West }
349
+ ```
350
+ **After:**
351
+ ```typescript
352
+ // Const object + type — tree-shakeable, maps cleanly to JS
353
+ const Direction = { North: 'North', South: 'South', East: 'East', West: 'West' } as const;
354
+ type Direction = typeof Direction[keyof typeof Direction];
355
+ ```
356
+
357
+ ---
358
+
359
+ ## Item 62: Don't Consider Migration Complete Until You Enable `noImplicitAny`
360
+
361
+ The final step of any JS→TS migration. Without it, TypeScript silently accepts untyped code.
362
+
363
+ ```json
364
+ // tsconfig.json — final migration milestone
365
+ {
366
+ "compilerOptions": {
367
+ "strict": true, // includes noImplicitAny and strictNullChecks
368
+ "noImplicitAny": true // explicit — every value must have a type
369
+ }
370
+ }
371
+ ```
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ review.py — Pre-analysis script for Effective TypeScript reviews.
4
+ Usage: python review.py <file.ts|file.tsx>
5
+
6
+ Scans a TypeScript source file for anti-patterns from the book's 62 items:
7
+ any usage, type assertions, object wrapper types, non-null assertions,
8
+ missing strict mode, interface-of-unions, plain string types, and more.
9
+ """
10
+
11
+ import re
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
16
+ CHECKS = [
17
+ (
18
+ r":\s*any\b",
19
+ "Item 5/38: any type annotation",
20
+ "replace with a specific type, generic parameter, or unknown for truly unknown values",
21
+ ),
22
+ (
23
+ r"\bas\s+any\b",
24
+ "Item 38/40: 'as any' assertion",
25
+ "scope 'as any' as narrowly as possible — hide inside a well-typed wrapper function; prefer 'as unknown as T' for safer double assertion",
26
+ ),
27
+ (
28
+ r"\bString\b|\bNumber\b|\bBoolean\b|\bObject\b|\bSymbol\b",
29
+ "Item 10: Object wrapper type (String/Number/Boolean)",
30
+ "use primitive types: string, number, boolean — never the wrapper class types",
31
+ ),
32
+ (
33
+ r"!\.",
34
+ "Item 28/31: Non-null assertion (!).",
35
+ "non-null assertions are usually a symptom of an imprecise type — fix the type instead; consider optional chaining (?.) or a type guard",
36
+ ),
37
+ (
38
+ r"@ts-ignore|@ts-nocheck",
39
+ "Item 38: @ts-ignore suppresses type errors",
40
+ "fix the underlying type issue; if unavoidable use @ts-expect-error with a comment explaining why",
41
+ ),
42
+ (
43
+ r"function\s+\w+[^{]*\{[^}]{0,20}\}",
44
+ None, # skip — too noisy
45
+ None,
46
+ ),
47
+ (
48
+ r"interface\s+\w+\s*\{[^}]*\?[^}]*\?[^}]*\}",
49
+ "Item 32: Interface with multiple optional fields",
50
+ "multiple optional fields that have implicit relationships suggest an interface-of-unions — convert to a tagged discriminated union",
51
+ ),
52
+ (
53
+ r"param(?:eter)?\s*:\s*string(?!\s*[|&])",
54
+ "Item 33: Plain string parameter",
55
+ "consider a string literal union if the parameter has a finite set of valid values (e.g. 'asc' | 'desc')",
56
+ ),
57
+ (
58
+ r"\.json\(\)\s*as\s+\w",
59
+ "Item 9/40: Direct type assertion on .json()",
60
+ "assign to unknown first, then narrow: 'const raw: unknown = await res.json()' — assertion inside a well-typed wrapper is acceptable (Item 40)",
61
+ ),
62
+ (
63
+ r"Promise<any>",
64
+ "Item 38: Promise<any> return type",
65
+ "replace with Promise<unknown> or a concrete type — Promise<any> disables type checking on the resolved value",
66
+ ),
67
+ ]
68
+
69
+
70
+ def scan(source: str) -> list[dict]:
71
+ findings = []
72
+ lines = source.splitlines()
73
+ for lineno, line in enumerate(lines, start=1):
74
+ stripped = line.strip()
75
+ if stripped.startswith("//") or stripped.startswith("*"):
76
+ continue
77
+ for pattern, label, advice in CHECKS:
78
+ if label is None:
79
+ continue
80
+ if re.search(pattern, line):
81
+ findings.append({
82
+ "line": lineno,
83
+ "text": line.rstrip(),
84
+ "label": label,
85
+ "advice": advice,
86
+ })
87
+ return findings
88
+
89
+
90
+ def check_strict(source: str) -> bool:
91
+ """Returns True if this looks like a tsconfig with strict mode enabled."""
92
+ return bool(re.search(r'"strict"\s*:\s*true', source))
93
+
94
+
95
+ def sep(char="-", width=70) -> str:
96
+ return char * width
97
+
98
+
99
+ def main() -> None:
100
+ if len(sys.argv) < 2:
101
+ print("Usage: python review.py <file.ts|file.tsx>")
102
+ sys.exit(1)
103
+
104
+ path = Path(sys.argv[1])
105
+ if not path.exists():
106
+ print(f"Error: file not found: {path}")
107
+ sys.exit(1)
108
+
109
+ if path.suffix.lower() not in (".ts", ".tsx", ".json"):
110
+ print(f"Warning: expected .ts/.tsx, got '{path.suffix}' — continuing anyway")
111
+
112
+ source = path.read_text(encoding="utf-8", errors="replace")
113
+
114
+ # Special case: tsconfig.json
115
+ if path.name == "tsconfig.json":
116
+ print(sep("="))
117
+ print("EFFECTIVE TYPESCRIPT — TSCONFIG CHECK")
118
+ print(sep("="))
119
+ if check_strict(source):
120
+ print(" [OK] strict: true is enabled (Item 2)")
121
+ else:
122
+ print(" [!] strict: true is NOT enabled — Item 2: always enable strict mode")
123
+ print(" Add: \"strict\": true to compilerOptions")
124
+ print()
125
+ print(sep("="))
126
+ return
127
+
128
+ findings = scan(source)
129
+ groups: dict[str, list] = {}
130
+ for f in findings:
131
+ groups.setdefault(f["label"], []).append(f)
132
+
133
+ print(sep("="))
134
+ print("EFFECTIVE TYPESCRIPT — PRE-REVIEW REPORT")
135
+ print(sep("="))
136
+ print(f"File : {path}")
137
+ print(f"Lines : {len(source.splitlines())}")
138
+ print(f"Issues : {len(findings)} potential violations across {len(groups)} categories")
139
+ print()
140
+
141
+ if not findings:
142
+ print(" [OK] No common Effective TypeScript anti-patterns detected.")
143
+ print()
144
+ else:
145
+ for label, items in groups.items():
146
+ print(sep())
147
+ print(f" {label} ({len(items)} occurrence{'s' if len(items) != 1 else ''})")
148
+ print(sep())
149
+ print(f" Advice: {items[0]['advice']}")
150
+ print()
151
+ for item in items[:5]:
152
+ print(f" line {item['line']:>4}: {item['text'][:100]}")
153
+ if len(items) > 5:
154
+ print(f" ... and {len(items) - 5} more")
155
+ print()
156
+
157
+ severity = (
158
+ "HIGH" if len(findings) >= 5
159
+ else "MEDIUM" if len(findings) >= 2
160
+ else "LOW" if findings
161
+ else "NONE"
162
+ )
163
+ print(sep("="))
164
+ print(f"SEVERITY: {severity} | Key items: Item 2 (strict), Item 5/38 (any/unknown), Item 9 (assertions), Item 28/32 (tagged unions), Item 33 (literal types)")
165
+ print(sep("="))
166
+
167
+
168
+ if __name__ == "__main__":
169
+ main()