@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,335 @@
1
+ # Programming with Rust — Practices Catalog
2
+
3
+ Deep before/after examples for the most critical Rust idioms from each chapter group.
4
+
5
+ ---
6
+
7
+ ## Ownership: Borrow Instead of Clone (Ch 8)
8
+
9
+ **Before:**
10
+ ```rust
11
+ fn print_names(names: Vec<String>) { // consumes the Vec
12
+ for name in names {
13
+ println!("{name}");
14
+ }
15
+ }
16
+ // names is gone after this call
17
+ ```
18
+ **After:**
19
+ ```rust
20
+ fn print_names(names: &[String]) { // borrows a slice — Vec<String> derefs to &[String]
21
+ for name in names {
22
+ println!("{name}");
23
+ }
24
+ }
25
+ // caller keeps ownership
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Ownership: Move Semantics (Ch 8)
31
+
32
+ **Before:**
33
+ ```rust
34
+ let s1 = String::from("hello");
35
+ let s2 = s1; // s1 is MOVED into s2
36
+ println!("{s1}"); // compile error: s1 was moved
37
+ ```
38
+ **After:**
39
+ ```rust
40
+ let s1 = String::from("hello");
41
+ let s2 = s1.clone(); // explicit deep copy — both valid
42
+ println!("{s1} {s2}"); // both valid
43
+
44
+ // Or: borrow instead of cloning
45
+ let s3 = &s1; // borrow — s1 still owns the data
46
+ println!("{s1} {s3}");
47
+ ```
48
+
49
+ ---
50
+
51
+ ## References: Borrow Rules (Ch 10)
52
+
53
+ ```rust
54
+ let mut data = vec![1, 2, 3];
55
+
56
+ // OK: multiple immutable borrows
57
+ let a = &data;
58
+ let b = &data;
59
+ println!("{a:?} {b:?}");
60
+
61
+ // OK: one mutable borrow (after immutable borrows end)
62
+ let c = &mut data;
63
+ c.push(4);
64
+
65
+ // COMPILE ERROR: can't have mutable + immutable borrow at same time
66
+ // let d = &data;
67
+ // let e = &mut data; // error
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Lifetimes: Elision vs Annotation (Ch 9)
73
+
74
+ **Elision works (no annotation needed):**
75
+ ```rust
76
+ fn first_word(s: &str) -> &str { // compiler infers output lifetime = input lifetime
77
+ s.split_whitespace().next().unwrap_or("")
78
+ }
79
+ ```
80
+
81
+ **Annotation required (multiple inputs, ambiguous output):**
82
+ ```rust
83
+ // Without annotation — compiler can't tell which input the output borrows from
84
+ fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {
85
+ if s1.len() > s2.len() { s1 } else { s2 }
86
+ }
87
+ ```
88
+
89
+ **Struct holding a reference — must annotate:**
90
+ ```rust
91
+ struct Excerpt<'a> {
92
+ text: &'a str, // struct can't outlive the string it borrows
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Error Handling: Result + ? (Ch 12)
99
+
100
+ **Before:**
101
+ ```rust
102
+ fn read_username() -> String {
103
+ let f = std::fs::File::open("username.txt").unwrap();
104
+ let mut s = String::new();
105
+ std::io::Read::read_to_string(&mut std::io::BufReader::new(f), &mut s).unwrap();
106
+ s
107
+ }
108
+ ```
109
+ **After:**
110
+ ```rust
111
+ fn read_username() -> Result<String, std::io::Error> {
112
+ std::fs::read_to_string("username.txt") // ? propagates automatically
113
+ }
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Error Handling: Custom Error Types (Ch 12)
119
+
120
+ ```rust
121
+ use std::fmt;
122
+
123
+ #[derive(Debug)]
124
+ pub enum AppError {
125
+ Io(std::io::Error),
126
+ Parse(std::num::ParseIntError),
127
+ Custom(String),
128
+ }
129
+
130
+ impl fmt::Display for AppError {
131
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132
+ match self {
133
+ AppError::Io(e) => write!(f, "I/O: {e}"),
134
+ AppError::Parse(e) => write!(f, "parse: {e}"),
135
+ AppError::Custom(s) => write!(f, "{s}"),
136
+ }
137
+ }
138
+ }
139
+
140
+ impl std::error::Error for AppError {}
141
+
142
+ // Enables ? to convert std::io::Error → AppError automatically
143
+ impl From<std::io::Error> for AppError {
144
+ fn from(e: std::io::Error) -> Self { AppError::Io(e) }
145
+ }
146
+
147
+ impl From<std::num::ParseIntError> for AppError {
148
+ fn from(e: std::num::ParseIntError) -> Self { AppError::Parse(e) }
149
+ }
150
+
151
+ fn parse_port(s: &str) -> Result<u16, AppError> {
152
+ let port: i32 = s.parse()?; // ParseIntError → AppError via From
153
+ if port < 1 || port > 65535 {
154
+ return Err(AppError::Custom(format!("invalid port: {port}")));
155
+ }
156
+ Ok(port as u16)
157
+ }
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Traits: Static vs Dynamic Dispatch (Ch 17)
163
+
164
+ **Static dispatch — zero cost, preferred:**
165
+ ```rust
166
+ // Monomorphized at compile time — no runtime overhead
167
+ fn notify(item: &impl Summary) {
168
+ println!("Breaking news! {}", item.summarize());
169
+ }
170
+
171
+ // Equivalent with explicit generic:
172
+ fn notify<T: Summary>(item: &T) {
173
+ println!("Breaking news! {}", item.summarize());
174
+ }
175
+ ```
176
+
177
+ **Dynamic dispatch — use only for heterogeneous collections or plugins:**
178
+ ```rust
179
+ // Vtable lookup at runtime — small overhead, but enables mixed types
180
+ fn notify_all(items: &[Box<dyn Summary>]) {
181
+ for item in items {
182
+ println!("{}", item.summarize());
183
+ }
184
+ }
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Traits: Implementing Standard Traits (Ch 17)
190
+
191
+ ```rust
192
+ use std::fmt;
193
+
194
+ #[derive(Debug, Clone, PartialEq)] // derive common traits
195
+ struct Point {
196
+ x: f64,
197
+ y: f64,
198
+ }
199
+
200
+ // Display for user-facing output
201
+ impl fmt::Display for Point {
202
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203
+ write!(f, "({}, {})", self.x, self.y)
204
+ }
205
+ }
206
+
207
+ // From for ergonomic conversion
208
+ impl From<(f64, f64)> for Point {
209
+ fn from((x, y): (f64, f64)) -> Self {
210
+ Point { x, y }
211
+ }
212
+ }
213
+
214
+ let p: Point = (1.0, 2.0).into(); // uses From impl
215
+ println!("{p}"); // uses Display
216
+ println!("{p:?}"); // uses Debug
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Pattern Matching: Exhaustive match (Ch 15)
222
+
223
+ **Before:**
224
+ ```rust
225
+ let opt: Option<i32> = get_value();
226
+ match opt {
227
+ Some(x) => println!("{x}"),
228
+ _ => {} // silently ignores None — intent unclear
229
+ }
230
+ ```
231
+ **After:**
232
+ ```rust
233
+ // if let for single-variant match
234
+ if let Some(x) = get_value() {
235
+ println!("{x}");
236
+ }
237
+
238
+ // Exhaustive match when both branches matter
239
+ match get_value() {
240
+ Some(x) => println!("got {x}"),
241
+ None => println!("nothing"),
242
+ }
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Closures: move for Threads (Ch 16, 18)
248
+
249
+ **Before:**
250
+ ```rust
251
+ let name = String::from("Alice");
252
+ let handle = std::thread::spawn(|| {
253
+ println!("{name}"); // error: closure may outlive name
254
+ });
255
+ ```
256
+ **After:**
257
+ ```rust
258
+ let name = String::from("Alice");
259
+ let handle = std::thread::spawn(move || {
260
+ println!("{name}"); // name is moved into the closure — safe
261
+ });
262
+ handle.join().unwrap();
263
+ ```
264
+
265
+ ---
266
+
267
+ ## Concurrency: Arc<Mutex<T>> (Ch 19)
268
+
269
+ ```rust
270
+ use std::sync::{Arc, Mutex};
271
+ use std::thread;
272
+
273
+ fn main() {
274
+ let counter = Arc::new(Mutex::new(0u32));
275
+ let mut handles = vec![];
276
+
277
+ for _ in 0..10 {
278
+ let counter = Arc::clone(&counter); // clone the Arc, not the data
279
+ let handle = thread::spawn(move || {
280
+ let mut num = counter.lock().expect("mutex poisoned");
281
+ *num += 1;
282
+ });
283
+ handles.push(handle);
284
+ }
285
+
286
+ for handle in handles {
287
+ handle.join().unwrap();
288
+ }
289
+
290
+ println!("Result: {}", *counter.lock().unwrap()); // 10
291
+ }
292
+ ```
293
+
294
+ ---
295
+
296
+ ## Memory: RefCell for Interior Mutability (Ch 20)
297
+
298
+ Use `RefCell<T>` when you need mutability inside an otherwise immutable value (single-threaded only):
299
+
300
+ ```rust
301
+ use std::cell::RefCell;
302
+
303
+ struct Cache {
304
+ data: RefCell<Option<String>>, // interior mutability
305
+ }
306
+
307
+ impl Cache {
308
+ fn get(&self) -> String {
309
+ // borrow_mut even though &self is immutable
310
+ let mut data = self.data.borrow_mut();
311
+ if data.is_none() {
312
+ *data = Some(expensive_computation());
313
+ }
314
+ data.as_ref().unwrap().clone()
315
+ }
316
+ }
317
+ // For multi-threaded use, replace RefCell with Mutex
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Modules: Visibility (Ch 23)
323
+
324
+ ```rust
325
+ // lib.rs
326
+ pub mod api { // public module
327
+ pub struct Request { /* ... */ } // public type
328
+ pub(crate) fn validate() { } // crate-internal only
329
+ fn internal_helper() { } // private to module
330
+ }
331
+
332
+ mod storage { // private module — not part of public API
333
+ pub(super) fn save() { } // accessible to parent module only
334
+ }
335
+ ```
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ review.py — Pre-analysis script for Programming with Rust reviews.
4
+ Usage: python review.py <file.rs>
5
+
6
+ Scans a Rust source file for anti-patterns from the book:
7
+ unwrap misuse, unnecessary cloning, unsafe shared state, manual index loops,
8
+ missing Result return types, static mut, and more.
9
+ """
10
+
11
+ import re
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
16
+ CHECKS = [
17
+ (
18
+ r"\.unwrap\(\)",
19
+ "Ch 12: .unwrap()",
20
+ "panics on failure in production paths — use ?, .expect(\"reason\"), or match",
21
+ ),
22
+ (
23
+ r"\.clone\(\)",
24
+ "Ch 8: .clone()",
25
+ "verify cloning is necessary — prefer borrowing (&T or &mut T) to avoid heap allocation",
26
+ ),
27
+ (
28
+ r"static\s+mut\s+\w+",
29
+ "Ch 19: static mut",
30
+ "data race risk — replace with Arc<Mutex<T>> or std::sync::atomic types",
31
+ ),
32
+ (
33
+ r"unsafe\s*\{",
34
+ "Ch 20: unsafe block",
35
+ "minimize unsafe scope; add a // SAFETY: comment explaining the invariant being upheld",
36
+ ),
37
+ (
38
+ r"for\s+\w+\s+in\s+0\s*\.\.\s*\w+\.len\(\)",
39
+ "Ch 6: Manual index loop",
40
+ "use iterator adapters: for item in &collection, or .iter().enumerate() if index is needed",
41
+ ),
42
+ (
43
+ r"\bpanic!\s*\(",
44
+ "Ch 12: panic!()",
45
+ "panics should be reserved for unrecoverable programmer errors — use Result<T, E> for recoverable failures",
46
+ ),
47
+ (
48
+ r"Box<dyn\s+\w+>",
49
+ "Ch 17: dyn Trait (dynamic dispatch)",
50
+ "prefer impl Trait for static dispatch (zero-cost) unless you need a heterogeneous collection",
51
+ ),
52
+ (
53
+ r"Rc\s*::\s*(new|clone)\b",
54
+ "Ch 19: Rc usage",
55
+ "Rc is not Send — if shared across threads, use Arc instead",
56
+ ),
57
+ (
58
+ r"\.expect\s*\(\s*\)",
59
+ "Ch 12: .expect() with empty string",
60
+ "add a meaningful reason: .expect(\"invariant: config is always loaded before this point\")",
61
+ ),
62
+ ]
63
+
64
+
65
+ def scan(source: str) -> list[dict]:
66
+ findings = []
67
+ lines = source.splitlines()
68
+ for lineno, line in enumerate(lines, start=1):
69
+ stripped = line.strip()
70
+ if stripped.startswith("//"):
71
+ continue
72
+ for pattern, label, advice in CHECKS:
73
+ if re.search(pattern, line):
74
+ findings.append({
75
+ "line": lineno,
76
+ "text": line.rstrip(),
77
+ "label": label,
78
+ "advice": advice,
79
+ })
80
+ return findings
81
+
82
+
83
+ def sep(char="-", width=70) -> str:
84
+ return char * width
85
+
86
+
87
+ def main() -> None:
88
+ if len(sys.argv) < 2:
89
+ print("Usage: python review.py <file.rs>")
90
+ sys.exit(1)
91
+
92
+ path = Path(sys.argv[1])
93
+ if not path.exists():
94
+ print(f"Error: file not found: {path}")
95
+ sys.exit(1)
96
+
97
+ if path.suffix.lower() != ".rs":
98
+ print(f"Warning: expected a .rs file, got '{path.suffix}' — continuing anyway")
99
+
100
+ source = path.read_text(encoding="utf-8", errors="replace")
101
+ findings = scan(source)
102
+ groups: dict[str, list] = {}
103
+ for f in findings:
104
+ groups.setdefault(f["label"], []).append(f)
105
+
106
+ print(sep("="))
107
+ print("PROGRAMMING WITH RUST — PRE-REVIEW REPORT")
108
+ print(sep("="))
109
+ print(f"File : {path}")
110
+ print(f"Lines : {len(source.splitlines())}")
111
+ print(f"Issues : {len(findings)} potential anti-patterns across {len(groups)} categories")
112
+ print()
113
+
114
+ if not findings:
115
+ print(" [OK] No common Rust anti-patterns detected.")
116
+ print()
117
+ else:
118
+ for label, items in groups.items():
119
+ print(sep())
120
+ print(f" {label} ({len(items)} occurrence{'s' if len(items) != 1 else ''})")
121
+ print(sep())
122
+ print(f" Advice: {items[0]['advice']}")
123
+ print()
124
+ for item in items[:5]:
125
+ print(f" line {item['line']:>4}: {item['text'][:100]}")
126
+ if len(items) > 5:
127
+ print(f" ... and {len(items) - 5} more")
128
+ print()
129
+
130
+ severity = (
131
+ "HIGH" if len(findings) >= 5
132
+ else "MEDIUM" if len(findings) >= 2
133
+ else "LOW" if findings
134
+ else "NONE"
135
+ )
136
+ print(sep("="))
137
+ print(f"SEVERITY: {severity} | Key chapters: Ch 8 (ownership), Ch 12 (errors), Ch 17 (traits), Ch 19 (concurrency), Ch 20 (memory)")
138
+ print(sep("="))
139
+
140
+
141
+ if __name__ == "__main__":
142
+ main()