@peaske7/readit 0.2.1 → 0.3.0-rc.1

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 (367) hide show
  1. package/dist/.vite/manifest.json +1111 -0
  2. package/dist/assets/_basePickBy-BMMA4Tou.js +1 -0
  3. package/dist/assets/_baseUniq-D40qku1I.js +1 -0
  4. package/dist/assets/arc-Ckg65iy8.js +1 -0
  5. package/dist/assets/architecture-YZFGNWBL-Dv3EY0zV.js +1 -0
  6. package/dist/assets/architectureDiagram-Q4EWVU46-ClRss4cm.js +36 -0
  7. package/dist/assets/array-Bjz-wYpJ.js +1 -0
  8. package/dist/assets/blockDiagram-DXYQGD6D-CBcFvoK1.js +132 -0
  9. package/dist/assets/c4Diagram-AHTNJAMY-D4d3ZLam.js +10 -0
  10. package/dist/assets/channel-D9EJxDy_.js +1 -0
  11. package/dist/assets/chunk-2KRD3SAO-DaFfaCGO.js +1 -0
  12. package/dist/assets/chunk-336JU56O-yLEQoF0v.js +2 -0
  13. package/dist/assets/chunk-426QAEUC-Uyzd4wAA.js +1 -0
  14. package/dist/assets/chunk-4BX2VUAB-DRuTD7x5.js +1 -0
  15. package/dist/assets/chunk-4TB4RGXK-3xbpIi_o.js +206 -0
  16. package/dist/assets/chunk-55IACEB6-BExiaAoD.js +1 -0
  17. package/dist/assets/chunk-5FUZZQ4R-DatVvHnF.js +62 -0
  18. package/dist/assets/chunk-5PVQY5BW-BKgvrGh8.js +2 -0
  19. package/dist/assets/chunk-67CJDMHE-DMt8LNEX.js +1 -0
  20. package/dist/assets/chunk-7N4EOEYR-CzLGefVf.js +1 -0
  21. package/dist/assets/chunk-AA7GKIK3-B6GFAk4U.js +1 -0
  22. package/dist/assets/chunk-BSJP7CBP-BK29yehL.js +1 -0
  23. package/dist/assets/chunk-CIAEETIT-D7hBXImP.js +1 -0
  24. package/dist/assets/chunk-Dlc7tRH4.js +1 -0
  25. package/dist/assets/chunk-EDXVE4YY-PYJdlmyH.js +1 -0
  26. package/dist/assets/chunk-ENJZ2VHE-DUHKBv6x.js +10 -0
  27. package/dist/assets/chunk-FMBD7UC4-2FWyCCAV.js +15 -0
  28. package/dist/assets/chunk-FOC6F5B3-DKFHrt4K.js +1 -0
  29. package/dist/assets/chunk-ICPOFSXX-Bh__D0ec.js +122 -0
  30. package/dist/assets/chunk-K5T4RW27-D51O7IkG.js +94 -0
  31. package/dist/assets/chunk-KGLVRYIC-DMHSCH4T.js +1 -0
  32. package/dist/assets/chunk-LIHQZDEY-C2aANxt9.js +1 -0
  33. package/dist/assets/chunk-ORNJ4GCN-Db_37NRX.js +1 -0
  34. package/dist/assets/chunk-OYMX7WX6-BltXOJLJ.js +231 -0
  35. package/dist/assets/chunk-QZHKN3VN-8Lcg9gti.js +1 -0
  36. package/dist/assets/chunk-U2HBQHQK-ByS6tilY.js +70 -0
  37. package/dist/assets/chunk-X2U36JSP-Bm-4Gqg_.js +1 -0
  38. package/dist/assets/chunk-XPW4576I-Bqbompq4.js +32 -0
  39. package/dist/assets/chunk-YZCP3GAM-CsC0imPb.js +1 -0
  40. package/dist/assets/chunk-ZZ45TVLE-CG-CqfPC.js +1 -0
  41. package/dist/assets/classDiagram-6PBFFD2Q-Jy1uFUk4.js +1 -0
  42. package/dist/assets/classDiagram-v2-HSJHXN6E-ChiLl3rR.js +1 -0
  43. package/dist/assets/clone-BBjvuERA.js +1 -0
  44. package/dist/assets/cose-bilkent-S5V4N54A-q90QeGKv.js +1 -0
  45. package/dist/assets/cytoscape.esm-BfXff3fb.js +321 -0
  46. package/dist/assets/dagre-KV5264BT-BQWiLFJB.js +4 -0
  47. package/dist/assets/dagre-nn_aIZ2E.js +1 -0
  48. package/dist/assets/defaultLocale-BwmRmqJp.js +1 -0
  49. package/dist/assets/diagram-5BDNPKRD-CJa7Y97H.js +10 -0
  50. package/dist/assets/diagram-G4DWMVQ6-tVQGBWfY.js +24 -0
  51. package/dist/assets/diagram-MMDJMWI5-CpimFldm.js +43 -0
  52. package/dist/assets/diagram-TYMM5635-D11WQVgy.js +24 -0
  53. package/dist/assets/dist-BNz65Ibc.js +1 -0
  54. package/dist/assets/erDiagram-SMLLAGMA-C2bLd0jS.js +85 -0
  55. package/dist/assets/flowDiagram-DWJPFMVM-Kw3fOOLT.js +162 -0
  56. package/dist/assets/ganttDiagram-T4ZO3ILL-fyMhyE2X.js +292 -0
  57. package/dist/assets/gitGraph-7Q5UKJZL-BGFRt2qs.js +1 -0
  58. package/dist/assets/gitGraphDiagram-UUTBAWPF-D4JoiOvg.js +106 -0
  59. package/dist/assets/graphlib-DGcD9J2L.js +1 -0
  60. package/dist/assets/index-Cow3qpoq.css +2 -0
  61. package/dist/assets/index-DUf7okYi.js +14 -0
  62. package/dist/assets/info-OMHHGYJF-DI6-Z9vh.js +1 -0
  63. package/dist/assets/infoDiagram-42DDH7IO-D1ZkeMBy.js +2 -0
  64. package/dist/assets/init-TPm5RB77.js +1 -0
  65. package/dist/assets/isArrayLikeObject-69BLnVNM.js +1 -0
  66. package/dist/assets/isEmpty-DUS28g5f.js +1 -0
  67. package/dist/assets/ishikawaDiagram-UXIWVN3A-Dv8hzjZB.js +70 -0
  68. package/dist/assets/journeyDiagram-VCZTEJTY-COeB7F5r.js +139 -0
  69. package/dist/assets/kanban-definition-6JOO6SKY-BbYmxCYU.js +89 -0
  70. package/dist/assets/katex-5SGEXwpi.js +261 -0
  71. package/dist/assets/line-_v2NGEdn.js +1 -0
  72. package/dist/assets/linear-CXMqTN8N.js +1 -0
  73. package/dist/assets/mermaid-config-C8a4L22x.js +1 -0
  74. package/dist/assets/mermaid-parser.core-CFmphzPP.js +4 -0
  75. package/dist/assets/mermaid.core-DnHAupTp.js +11 -0
  76. package/dist/assets/mindmap-definition-QFDTVHPH-D7_lIep7.js +96 -0
  77. package/dist/assets/ordinal-D7l-8DAO.js +1 -0
  78. package/dist/assets/packet-4T2RLAQJ-DidW3JFc.js +1 -0
  79. package/dist/assets/path-BVpCanzE.js +1 -0
  80. package/dist/assets/pie-ZZUOXDRM-Bff2e5hg.js +1 -0
  81. package/dist/assets/pieDiagram-DEJITSTG-DDvYHCT_.js +30 -0
  82. package/dist/assets/quadrantDiagram-34T5L4WZ-DcLcIrdi.js +7 -0
  83. package/dist/assets/radar-PYXPWWZC-CsdZBH3M.js +1 -0
  84. package/dist/assets/requirementDiagram-MS252O5E-DLX6ld7D.js +84 -0
  85. package/dist/assets/rough.esm-BoTisKeL.js +1 -0
  86. package/dist/assets/sankeyDiagram-XADWPNL6-D-1GtsHM.js +10 -0
  87. package/dist/assets/sequenceDiagram-FGHM5R23-Bwxs0YQg.js +157 -0
  88. package/dist/assets/src-CrmkjRpa.js +1 -0
  89. package/dist/assets/stateDiagram-FHFEXIEX-DW7rOcnQ.js +1 -0
  90. package/dist/assets/stateDiagram-v2-QKLJ7IA2-Jm-24vQ2.js +1 -0
  91. package/dist/assets/timeline-definition-GMOUNBTQ-DVdHyzxS.js +120 -0
  92. package/dist/assets/treeView-SZITEDCU-DPKseaET.js +1 -0
  93. package/dist/assets/treemap-W4RFUUIX-DH-7GZe_.js +1 -0
  94. package/dist/assets/vennDiagram-DHZGUBPP-DJaC6xmI.js +34 -0
  95. package/dist/assets/wardley-RL74JXVD-AgyXyBN5.js +1 -0
  96. package/dist/assets/wardleyDiagram-NUSXRM2D-CTKERPKv.js +20 -0
  97. package/dist/assets/xychartDiagram-5P7HB3ND-BuExiLXc.js +7 -0
  98. package/{index.html → dist/index.html} +2 -1
  99. package/dist/index.js +2539 -0
  100. package/package.json +11 -1
  101. package/.agents/skills/remotion-best-practices/SKILL.md +0 -61
  102. package/.agents/skills/remotion-best-practices/rules/3d.md +0 -86
  103. package/.agents/skills/remotion-best-practices/rules/animations.md +0 -27
  104. package/.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +0 -178
  105. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +0 -100
  106. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +0 -108
  107. package/.agents/skills/remotion-best-practices/rules/assets.md +0 -78
  108. package/.agents/skills/remotion-best-practices/rules/audio-visualization.md +0 -198
  109. package/.agents/skills/remotion-best-practices/rules/audio.md +0 -169
  110. package/.agents/skills/remotion-best-practices/rules/calculate-metadata.md +0 -134
  111. package/.agents/skills/remotion-best-practices/rules/can-decode.md +0 -75
  112. package/.agents/skills/remotion-best-practices/rules/charts.md +0 -120
  113. package/.agents/skills/remotion-best-practices/rules/compositions.md +0 -154
  114. package/.agents/skills/remotion-best-practices/rules/display-captions.md +0 -184
  115. package/.agents/skills/remotion-best-practices/rules/extract-frames.md +0 -229
  116. package/.agents/skills/remotion-best-practices/rules/ffmpeg.md +0 -38
  117. package/.agents/skills/remotion-best-practices/rules/fonts.md +0 -152
  118. package/.agents/skills/remotion-best-practices/rules/get-audio-duration.md +0 -58
  119. package/.agents/skills/remotion-best-practices/rules/get-video-dimensions.md +0 -68
  120. package/.agents/skills/remotion-best-practices/rules/get-video-duration.md +0 -60
  121. package/.agents/skills/remotion-best-practices/rules/gifs.md +0 -141
  122. package/.agents/skills/remotion-best-practices/rules/images.md +0 -134
  123. package/.agents/skills/remotion-best-practices/rules/import-srt-captions.md +0 -69
  124. package/.agents/skills/remotion-best-practices/rules/light-leaks.md +0 -73
  125. package/.agents/skills/remotion-best-practices/rules/lottie.md +0 -70
  126. package/.agents/skills/remotion-best-practices/rules/maps.md +0 -412
  127. package/.agents/skills/remotion-best-practices/rules/measuring-dom-nodes.md +0 -34
  128. package/.agents/skills/remotion-best-practices/rules/measuring-text.md +0 -140
  129. package/.agents/skills/remotion-best-practices/rules/parameters.md +0 -109
  130. package/.agents/skills/remotion-best-practices/rules/sequencing.md +0 -118
  131. package/.agents/skills/remotion-best-practices/rules/sfx.md +0 -26
  132. package/.agents/skills/remotion-best-practices/rules/subtitles.md +0 -36
  133. package/.agents/skills/remotion-best-practices/rules/tailwind.md +0 -11
  134. package/.agents/skills/remotion-best-practices/rules/text-animations.md +0 -20
  135. package/.agents/skills/remotion-best-practices/rules/timing.md +0 -179
  136. package/.agents/skills/remotion-best-practices/rules/transcribe-captions.md +0 -70
  137. package/.agents/skills/remotion-best-practices/rules/transitions.md +0 -197
  138. package/.agents/skills/remotion-best-practices/rules/transparent-videos.md +0 -106
  139. package/.agents/skills/remotion-best-practices/rules/trimming.md +0 -51
  140. package/.agents/skills/remotion-best-practices/rules/videos.md +0 -171
  141. package/.agents/skills/remotion-best-practices/rules/voiceover.md +0 -99
  142. package/.agents/skills/simple/SKILL.md +0 -52
  143. package/.agents/skills/vercel-react-best-practices/AGENTS.md +0 -3254
  144. package/.agents/skills/vercel-react-best-practices/README.md +0 -123
  145. package/.agents/skills/vercel-react-best-practices/SKILL.md +0 -141
  146. package/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  147. package/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
  148. package/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
  149. package/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  150. package/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  151. package/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
  152. package/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  153. package/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  154. package/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  155. package/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  156. package/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  157. package/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  158. package/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  159. package/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  160. package/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  161. package/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  162. package/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  163. package/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
  164. package/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  165. package/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  166. package/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  167. package/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  168. package/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  169. package/.agents/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
  170. package/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  171. package/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  172. package/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  173. package/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  174. package/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  175. package/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  176. package/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  177. package/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  178. package/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  179. package/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  180. package/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  181. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  182. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
  183. package/.agents/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
  184. package/.agents/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
  185. package/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  186. package/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
  187. package/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  188. package/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  189. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
  190. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  191. package/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  192. package/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  193. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
  194. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  195. package/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
  196. package/.agents/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
  197. package/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
  198. package/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  199. package/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
  200. package/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  201. package/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
  202. package/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  203. package/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  204. package/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
  205. package/.agents/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
  206. package/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  207. package/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  208. package/.claude/CLAUDE.md +0 -184
  209. package/.claude/commands/review.md +0 -120
  210. package/.claude/commands/sync-docs.md +0 -71
  211. package/.claude/roadmap.md +0 -121
  212. package/.claude/rules/style-guide.md +0 -830
  213. package/.claude/settings.json +0 -18
  214. package/.claude/user-stories.md +0 -333
  215. package/AGENTS.md +0 -68
  216. package/Makefile +0 -32
  217. package/biome.json +0 -79
  218. package/bun.lock +0 -854
  219. package/bunfig.toml +0 -2
  220. package/docs/design.md +0 -563
  221. package/docs/perf-baseline.md +0 -130
  222. package/docs/plans/2026-03-13-client-mode-design.md +0 -86
  223. package/docs/plans/2026-03-13-client-mode-plan.md +0 -605
  224. package/docs/plans/2026-03-13-keyboard-shortcuts-design.md +0 -129
  225. package/docs/plans/2026-03-13-keyboard-shortcuts-plan.md +0 -1471
  226. package/docs/plans/2026-03-13-multi-document-design.md +0 -183
  227. package/docs/plans/2026-03-13-performance-benchmarks-design.md +0 -121
  228. package/docs/superpowers/plans/2026-03-26-surgical-pruning.md +0 -1176
  229. package/docs/superpowers/specs/2026-03-27-go-server-rewrite-design.md +0 -284
  230. package/e2e/comments.spec.ts +0 -81
  231. package/e2e/document-load.spec.ts +0 -32
  232. package/e2e/export.spec.ts +0 -58
  233. package/e2e/fixtures/sample.md +0 -7
  234. package/e2e/perf/add-comment.spec.ts +0 -116
  235. package/e2e/perf/fixtures/generate.ts +0 -327
  236. package/e2e/perf/initial-load.spec.ts +0 -49
  237. package/e2e/perf/perf.setup.ts +0 -23
  238. package/e2e/perf/perf.teardown.ts +0 -9
  239. package/e2e/perf/screenshot-final.png +0 -0
  240. package/e2e/perf/scroll.spec.ts +0 -39
  241. package/e2e/perf/tab-switch.spec.ts +0 -69
  242. package/e2e/perf/text-selection.spec.ts +0 -119
  243. package/e2e/perf/utils/metrics.ts +0 -350
  244. package/e2e/perf/utils/perf-cli.ts +0 -86
  245. package/e2e/persistence-file.spec.ts +0 -357
  246. package/e2e/utils/cli.ts +0 -84
  247. package/e2e/utils/selection.ts +0 -79
  248. package/go/cmd/readit/main.go +0 -416
  249. package/go/go.mod +0 -20
  250. package/go/go.sum +0 -41
  251. package/go/internal/server/anchor.go +0 -302
  252. package/go/internal/server/anchor_test.go +0 -111
  253. package/go/internal/server/comments.go +0 -390
  254. package/go/internal/server/documents.go +0 -113
  255. package/go/internal/server/embed.go +0 -17
  256. package/go/internal/server/headings.go +0 -33
  257. package/go/internal/server/headings_test.go +0 -75
  258. package/go/internal/server/htmltext.go +0 -123
  259. package/go/internal/server/markdown.go +0 -157
  260. package/go/internal/server/markdown_bench_test.go +0 -42
  261. package/go/internal/server/markdown_test.go +0 -79
  262. package/go/internal/server/server.go +0 -453
  263. package/go/internal/server/server_bench_test.go +0 -122
  264. package/go/internal/server/settings.go +0 -110
  265. package/go/internal/server/sse.go +0 -140
  266. package/go/internal/server/storage.go +0 -275
  267. package/go/internal/server/storage_test.go +0 -118
  268. package/go/internal/server/template.go +0 -66
  269. package/go/internal/server/types.go +0 -101
  270. package/go/internal/server/watcher.go +0 -74
  271. package/lefthook.yml +0 -8
  272. package/nvim-readit/lua/readit/health.lua +0 -64
  273. package/nvim-readit/lua/readit/init.lua +0 -463
  274. package/nvim-readit/plugin/readit.lua +0 -19
  275. package/playwright.config.ts +0 -34
  276. package/skills-lock.json +0 -20
  277. package/src/App.svelte +0 -881
  278. package/src/cli.ts +0 -881
  279. package/src/components/ActionsMenu.svelte +0 -95
  280. package/src/components/CommentBadge.svelte +0 -67
  281. package/src/components/CommentErrorBanner.svelte +0 -33
  282. package/src/components/CommentInput.svelte +0 -75
  283. package/src/components/CommentListItem.svelte +0 -95
  284. package/src/components/CommentManager.svelte +0 -129
  285. package/src/components/CommentNav.svelte +0 -109
  286. package/src/components/DocumentViewer.svelte +0 -218
  287. package/src/components/FloatingComment.svelte +0 -107
  288. package/src/components/Header.svelte +0 -76
  289. package/src/components/InlineEditor.svelte +0 -72
  290. package/src/components/MarginNote.svelte +0 -167
  291. package/src/components/MarginNotesContainer.svelte +0 -33
  292. package/src/components/RawModal.svelte +0 -126
  293. package/src/components/ReanchorConfirm.svelte +0 -30
  294. package/src/components/SettingsModal.svelte +0 -220
  295. package/src/components/ShortcutCapture.svelte +0 -82
  296. package/src/components/ShortcutList.svelte +0 -145
  297. package/src/components/TabBar.svelte +0 -52
  298. package/src/components/TableOfContents.svelte +0 -125
  299. package/src/components/ui/ActionLink.svelte +0 -40
  300. package/src/components/ui/Button.svelte +0 -53
  301. package/src/components/ui/Dialog.svelte +0 -97
  302. package/src/components/ui/DropdownMenu.svelte +0 -85
  303. package/src/components/ui/DropdownMenuItem.svelte +0 -38
  304. package/src/components/ui/DropdownMenuSeparator.svelte +0 -11
  305. package/src/components/ui/Text.svelte +0 -42
  306. package/src/env.d.ts +0 -6
  307. package/src/index.css +0 -754
  308. package/src/lib/__fixtures__/bench-data.ts +0 -114
  309. package/src/lib/anchor.bench.ts +0 -91
  310. package/src/lib/anchor.test.ts +0 -527
  311. package/src/lib/anchor.ts +0 -381
  312. package/src/lib/comment-storage.bench.ts +0 -49
  313. package/src/lib/comment-storage.test.ts +0 -632
  314. package/src/lib/comment-storage.ts +0 -222
  315. package/src/lib/export.bench.ts +0 -21
  316. package/src/lib/export.ts +0 -36
  317. package/src/lib/headings.test.ts +0 -103
  318. package/src/lib/headings.ts +0 -44
  319. package/src/lib/highlight/core.test.ts +0 -93
  320. package/src/lib/highlight/dom.ts +0 -187
  321. package/src/lib/highlight/highlight-registry.ts +0 -221
  322. package/src/lib/highlight/highlight.bench.ts +0 -92
  323. package/src/lib/highlight/highlighter.ts +0 -247
  324. package/src/lib/highlight/resolver.ts +0 -38
  325. package/src/lib/highlight/types.ts +0 -17
  326. package/src/lib/html-text.test.ts +0 -162
  327. package/src/lib/html-text.ts +0 -161
  328. package/src/lib/i18n/en.ts +0 -116
  329. package/src/lib/i18n/index.ts +0 -3
  330. package/src/lib/i18n/ja.ts +0 -118
  331. package/src/lib/i18n/translations.ts +0 -27
  332. package/src/lib/i18n/types.ts +0 -122
  333. package/src/lib/margin-layout.bench.ts +0 -61
  334. package/src/lib/margin-layout.ts +0 -71
  335. package/src/lib/markdown-renderer.test.ts +0 -154
  336. package/src/lib/markdown-renderer.ts +0 -177
  337. package/src/lib/mermaid-config.ts +0 -38
  338. package/src/lib/mermaid-renderer.ts +0 -162
  339. package/src/lib/mermaid-worker.ts +0 -60
  340. package/src/lib/positions.ts +0 -157
  341. package/src/lib/shortcut-registry.ts +0 -244
  342. package/src/lib/utils.ts +0 -15
  343. package/src/main.ts +0 -16
  344. package/src/schema.ts +0 -92
  345. package/src/server.ts +0 -1220
  346. package/src/stores/app.svelte.ts +0 -231
  347. package/src/stores/locale.svelte.ts +0 -46
  348. package/src/stores/settings.svelte.ts +0 -90
  349. package/src/stores/shortcuts.svelte.ts +0 -104
  350. package/src/stores/ui.svelte.ts +0 -12
  351. package/src/template.ts +0 -104
  352. package/src/test-setup.ts +0 -48
  353. package/svelte.config.js +0 -5
  354. package/test.md +0 -74
  355. package/tsconfig.cli.json +0 -12
  356. package/tsconfig.json +0 -20
  357. package/vite.config.ts +0 -47
  358. package/vitest.config.ts +0 -15
  359. package/vscode-readit/.mcp.json +0 -7
  360. package/vscode-readit/.vscodeignore +0 -7
  361. package/vscode-readit/bun.lock +0 -78
  362. package/vscode-readit/icon.svg +0 -10
  363. package/vscode-readit/package.json +0 -110
  364. package/vscode-readit/src/extension.ts +0 -117
  365. package/vscode-readit/src/server-manager.ts +0 -272
  366. package/vscode-readit/src/webview-provider.ts +0 -204
  367. package/vscode-readit/tsconfig.json +0 -20
@@ -1,390 +0,0 @@
1
- package server
2
-
3
- import (
4
- "fmt"
5
- "log"
6
- "net/http"
7
- "os"
8
- "strings"
9
- "sync"
10
- )
11
-
12
- func (s *Server) commentLock(path string) *sync.Mutex {
13
- s.commentFileMu.Lock()
14
- defer s.commentFileMu.Unlock()
15
- mu, ok := s.commentFileLocks[path]
16
- if !ok {
17
- mu = &sync.Mutex{}
18
- s.commentFileLocks[path] = mu
19
- }
20
- return mu
21
- }
22
-
23
- func (s *Server) resolveCommentsFor(path string, state *FileState) []Comment {
24
- commentPath, err := CommentPath(path)
25
- if err != nil {
26
- log.Printf("Warning: failed to resolve comment path for %s: %v", path, err)
27
- return []Comment{}
28
- }
29
-
30
- s.commentCacheMu.RLock()
31
- cached := s.commentCache[path]
32
- s.commentCacheMu.RUnlock()
33
-
34
- sourceHash := ComputeHash(state.Content)
35
-
36
- info, err := os.Stat(commentPath)
37
- if err != nil {
38
- if os.IsNotExist(err) {
39
- return []Comment{}
40
- }
41
- log.Printf("Warning: unexpected error checking comment file %s: %v", commentPath, err)
42
- return []Comment{}
43
- }
44
-
45
- mtimeMs := info.ModTime().UnixMilli()
46
- if cached != nil && cached.sourceHash == sourceHash && cached.commentMtimeMs == mtimeMs {
47
- return cached.comments
48
- }
49
-
50
- data, err := os.ReadFile(commentPath)
51
- if err != nil {
52
- return []Comment{}
53
- }
54
-
55
- cf, err := ParseCommentFile(data)
56
- if err != nil {
57
- return []Comment{}
58
- }
59
-
60
- sourceContent := string(state.Content)
61
- domText := ExtractTextFromHTML(state.RenderedHTML)
62
-
63
- resolved := make([]Comment, 0, len(cf.Comments))
64
- for _, c := range cf.Comments {
65
- searchText := c.SelectedText
66
- if c.AnchorPrefix != "" {
67
- searchText = c.AnchorPrefix
68
- }
69
-
70
- result := FindAnchorWithFallback(sourceContent, searchText, c.LineHint)
71
- if result != nil {
72
- c.StartOffset = result.StartOffset
73
- c.EndOffset = result.EndOffset
74
- c.AnchorConfidence = result.Confidence
75
-
76
- if start, end, ok := FindTextPosition(domText, searchText, result.StartOffset); ok {
77
- c.StartOffset = start
78
- c.EndOffset = end
79
- }
80
- } else {
81
- c.AnchorConfidence = AnchorUnresolved
82
- }
83
-
84
- resolved = append(resolved, c)
85
- }
86
-
87
- s.commentCacheMu.Lock()
88
- s.commentCache[path] = &resolvedCacheEntry{
89
- commentMtimeMs: mtimeMs,
90
- sourceHash: sourceHash,
91
- comments: resolved,
92
- }
93
- s.commentCacheMu.Unlock()
94
-
95
- return resolved
96
- }
97
-
98
- func (s *Server) listComments(w http.ResponseWriter, r *http.Request) {
99
- path := s.resolveFilePath(r)
100
- state := s.getFileState(path)
101
- if state == nil {
102
- writeError(w, http.StatusNotFound, "document not found")
103
- return
104
- }
105
-
106
- comments := s.resolveCommentsFor(path, state)
107
- writeJSON(w, http.StatusOK, map[string]any{"comments": comments})
108
- }
109
-
110
- func (s *Server) createComment(w http.ResponseWriter, r *http.Request) {
111
- path := s.resolveFilePath(r)
112
- state := s.getFileState(path)
113
- if state == nil {
114
- writeError(w, http.StatusNotFound, "document not found")
115
- return
116
- }
117
-
118
- var body struct {
119
- SelectedText string `json:"selectedText"`
120
- Comment string `json:"comment"`
121
- StartOffset int `json:"startOffset"`
122
- EndOffset int `json:"endOffset"`
123
- }
124
- if err := readJSON(r, &body); err != nil {
125
- writeError(w, http.StatusBadRequest, "invalid request body")
126
- return
127
- }
128
-
129
- if body.SelectedText == "" || body.Comment == "" {
130
- writeError(w, http.StatusBadRequest, "selectedText and comment are required")
131
- return
132
- }
133
-
134
- c := CreateComment(body.SelectedText, body.Comment, body.StartOffset, body.EndOffset, string(state.Content))
135
-
136
- mu := s.commentLock(path)
137
- mu.Lock()
138
- defer mu.Unlock()
139
-
140
- commentPath, err := CommentPath(path)
141
- if err != nil {
142
- writeError(w, http.StatusInternalServerError, "failed to resolve comment path")
143
- return
144
- }
145
- cf := CommentFile{
146
- Source: path,
147
- Hash: ComputeHash(state.Content),
148
- Version: FormatVersion,
149
- }
150
-
151
- if data, err := os.ReadFile(commentPath); err == nil {
152
- parsed, parseErr := ParseCommentFile(data)
153
- if parseErr != nil {
154
- writeError(w, http.StatusInternalServerError, fmt.Sprintf("failed to parse existing comment file: %v", parseErr))
155
- return
156
- }
157
- cf = parsed
158
- } else if !os.IsNotExist(err) {
159
- writeError(w, http.StatusInternalServerError, fmt.Sprintf("failed to read comment file: %v", err))
160
- return
161
- }
162
- cf.Hash = ComputeHash(state.Content)
163
- cf.Comments = append(cf.Comments, c)
164
-
165
- if err := WriteCommentFile(commentPath, cf); err != nil {
166
- writeError(w, http.StatusInternalServerError, fmt.Sprintf("failed to save comment: %v", err))
167
- return
168
- }
169
- s.invalidateCommentCache(path)
170
-
171
- writeJSON(w, http.StatusCreated, map[string]any{"comment": c})
172
- }
173
-
174
- func (s *Server) updateComment(w http.ResponseWriter, r *http.Request) {
175
- path := s.resolveFilePath(r)
176
- commentID := r.PathValue("id")
177
-
178
- var body struct {
179
- Comment string `json:"comment"`
180
- }
181
- if err := readJSON(r, &body); err != nil {
182
- writeError(w, http.StatusBadRequest, "invalid request body")
183
- return
184
- }
185
-
186
- mu := s.commentLock(path)
187
- mu.Lock()
188
- defer mu.Unlock()
189
-
190
- commentPath, err := CommentPath(path)
191
- if err != nil {
192
- writeError(w, http.StatusInternalServerError, "failed to resolve comment path")
193
- return
194
- }
195
- data, err := os.ReadFile(commentPath)
196
- if err != nil {
197
- writeError(w, http.StatusNotFound, "comment file not found")
198
- return
199
- }
200
-
201
- cf, err := ParseCommentFile(data)
202
- if err != nil {
203
- writeError(w, http.StatusInternalServerError, "failed to parse comments")
204
- return
205
- }
206
-
207
- for i := range cf.Comments {
208
- if cf.Comments[i].ID == commentID {
209
- cf.Comments[i].Comment = strings.TrimSpace(body.Comment)
210
-
211
- if err := WriteCommentFile(commentPath, cf); err != nil {
212
- writeError(w, http.StatusInternalServerError, "failed to save")
213
- return
214
- }
215
- s.invalidateCommentCache(path)
216
- writeJSON(w, http.StatusOK, map[string]any{"comment": cf.Comments[i]})
217
- return
218
- }
219
- }
220
-
221
- writeError(w, http.StatusNotFound, "comment not found")
222
- }
223
-
224
- func (s *Server) deleteComment(w http.ResponseWriter, r *http.Request) {
225
- path := s.resolveFilePath(r)
226
- commentID := r.PathValue("id")
227
-
228
- mu := s.commentLock(path)
229
- mu.Lock()
230
- defer mu.Unlock()
231
-
232
- commentPath, err := CommentPath(path)
233
- if err != nil {
234
- writeError(w, http.StatusInternalServerError, "failed to resolve comment path")
235
- return
236
- }
237
- data, err := os.ReadFile(commentPath)
238
- if err != nil {
239
- writeError(w, http.StatusNotFound, "comment file not found")
240
- return
241
- }
242
-
243
- cf, err := ParseCommentFile(data)
244
- if err != nil {
245
- writeError(w, http.StatusInternalServerError, "failed to parse comments")
246
- return
247
- }
248
-
249
- filtered := make([]Comment, 0, len(cf.Comments))
250
- for _, c := range cf.Comments {
251
- if c.ID != commentID {
252
- filtered = append(filtered, c)
253
- }
254
- }
255
-
256
- if len(filtered) == len(cf.Comments) {
257
- writeError(w, http.StatusNotFound, "comment not found")
258
- return
259
- }
260
-
261
- if len(filtered) == 0 {
262
- if err := os.Remove(commentPath); err != nil && !os.IsNotExist(err) {
263
- writeError(w, http.StatusInternalServerError, "failed to delete comment file")
264
- return
265
- }
266
- } else {
267
- cf.Comments = filtered
268
- if err := WriteCommentFile(commentPath, cf); err != nil {
269
- writeError(w, http.StatusInternalServerError, "failed to save comments")
270
- return
271
- }
272
- }
273
- s.invalidateCommentCache(path)
274
-
275
- writeJSON(w, http.StatusOK, map[string]bool{"success": true})
276
- }
277
-
278
- func (s *Server) deleteAllComments(w http.ResponseWriter, r *http.Request) {
279
- path := s.resolveFilePath(r)
280
-
281
- mu := s.commentLock(path)
282
- mu.Lock()
283
- defer mu.Unlock()
284
-
285
- commentPath, err := CommentPath(path)
286
- if err != nil {
287
- writeError(w, http.StatusInternalServerError, "failed to resolve comment path")
288
- return
289
- }
290
- if err := os.Remove(commentPath); err != nil && !os.IsNotExist(err) {
291
- writeError(w, http.StatusInternalServerError, "failed to delete comment file")
292
- return
293
- }
294
- s.invalidateCommentCache(path)
295
- writeJSON(w, http.StatusOK, map[string]bool{"success": true})
296
- }
297
-
298
- func (s *Server) reanchorComment(w http.ResponseWriter, r *http.Request) {
299
- path := s.resolveFilePath(r)
300
- state := s.getFileState(path)
301
- if state == nil {
302
- writeError(w, http.StatusNotFound, "document not found")
303
- return
304
- }
305
-
306
- commentID := r.PathValue("id")
307
-
308
- var body struct {
309
- SelectedText string `json:"selectedText"`
310
- StartOffset int `json:"startOffset"`
311
- EndOffset int `json:"endOffset"`
312
- }
313
- if err := readJSON(r, &body); err != nil {
314
- writeError(w, http.StatusBadRequest, "invalid request body")
315
- return
316
- }
317
-
318
- mu := s.commentLock(path)
319
- mu.Lock()
320
- defer mu.Unlock()
321
-
322
- commentPath, err := CommentPath(path)
323
- if err != nil {
324
- writeError(w, http.StatusInternalServerError, "failed to resolve comment path")
325
- return
326
- }
327
- data, err := os.ReadFile(commentPath)
328
- if err != nil {
329
- writeError(w, http.StatusNotFound, "comment file not found")
330
- return
331
- }
332
-
333
- cf, err := ParseCommentFile(data)
334
- if err != nil {
335
- writeError(w, http.StatusInternalServerError, "failed to parse comments")
336
- return
337
- }
338
-
339
- sourceContent := string(state.Content)
340
- for i := range cf.Comments {
341
- if cf.Comments[i].ID == commentID {
342
- truncated := TruncateSelection(body.SelectedText)
343
- cf.Comments[i].SelectedText = truncated
344
- cf.Comments[i].StartOffset = body.StartOffset
345
- cf.Comments[i].EndOffset = body.EndOffset
346
- cf.Comments[i].LineHint = GetLineHint(sourceContent, body.StartOffset, body.EndOffset)
347
- cf.Comments[i].AnchorConfidence = AnchorExact
348
-
349
- if len(body.SelectedText) > MaxSelectionLength {
350
- cf.Comments[i].AnchorPrefix = body.SelectedText[:min(AnchorPrefixLength, len(body.SelectedText))]
351
- } else {
352
- cf.Comments[i].AnchorPrefix = ""
353
- }
354
-
355
- cf.Hash = ComputeHash(state.Content)
356
- if err := WriteCommentFile(commentPath, cf); err != nil {
357
- writeError(w, http.StatusInternalServerError, "failed to save")
358
- return
359
- }
360
- s.invalidateCommentCache(path)
361
- writeJSON(w, http.StatusOK, map[string]any{"comment": cf.Comments[i]})
362
- return
363
- }
364
- }
365
-
366
- writeError(w, http.StatusNotFound, "comment not found")
367
- }
368
-
369
- func (s *Server) rawComments(w http.ResponseWriter, r *http.Request) {
370
- path := s.resolveFilePath(r)
371
- commentPath, err := CommentPath(path)
372
- if err != nil {
373
- writeError(w, http.StatusInternalServerError, "failed to resolve comment path")
374
- return
375
- }
376
-
377
- data, err := os.ReadFile(commentPath)
378
- if err != nil {
379
- writeJSON(w, http.StatusOK, map[string]any{
380
- "content": nil,
381
- "path": commentPath,
382
- })
383
- return
384
- }
385
-
386
- writeJSON(w, http.StatusOK, map[string]any{
387
- "content": string(data),
388
- "path": commentPath,
389
- })
390
- }
@@ -1,113 +0,0 @@
1
- package server
2
-
3
- import (
4
- "encoding/json"
5
- "net/http"
6
- "path/filepath"
7
- "strings"
8
- )
9
-
10
- func (s *Server) listDocuments(w http.ResponseWriter, r *http.Request) {
11
- s.mu.RLock()
12
- files := make([]FileRef, 0, len(s.fileOrder))
13
- for _, p := range s.fileOrder {
14
- if f, ok := s.files[p]; ok {
15
- files = append(files, FileRef{Path: p, FileName: f.FileName})
16
- }
17
- }
18
- clean := s.clean
19
- workingDir := s.workingDir
20
- s.mu.RUnlock()
21
-
22
- writeJSON(w, http.StatusOK, map[string]any{
23
- "files": files,
24
- "clean": clean,
25
- "workingDirectory": workingDir,
26
- })
27
- }
28
-
29
- func (s *Server) addDocument(w http.ResponseWriter, r *http.Request) {
30
- var body struct {
31
- Path string `json:"path"`
32
- }
33
- if err := readJSON(r, &body); err != nil || body.Path == "" {
34
- writeError(w, http.StatusBadRequest, "path is required")
35
- return
36
- }
37
-
38
- absPath, err := filepath.Abs(body.Path)
39
- if err != nil {
40
- writeError(w, http.StatusBadRequest, "invalid path")
41
- return
42
- }
43
- absPath, err = filepath.EvalSymlinks(absPath)
44
- if err != nil {
45
- writeError(w, http.StatusNotFound, "file not found")
46
- return
47
- }
48
-
49
- if !isMarkdownFile(absPath) {
50
- writeError(w, http.StatusBadRequest, "only markdown files are supported")
51
- return
52
- }
53
-
54
- s.mu.RLock()
55
- _, exists := s.files[absPath]
56
- s.mu.RUnlock()
57
-
58
- if exists {
59
- writeJSON(w, http.StatusOK, map[string]string{
60
- "path": absPath,
61
- "fileName": filepath.Base(absPath),
62
- "status": "present",
63
- })
64
- return
65
- }
66
-
67
- if err := s.loadFile(FileEntry{FilePath: absPath}); err != nil {
68
- writeError(w, http.StatusInternalServerError, "failed to load file")
69
- return
70
- }
71
-
72
- fileName := filepath.Base(absPath)
73
-
74
- event, _ := json.Marshal(map[string]string{
75
- "type": "document-added",
76
- "path": absPath,
77
- "fileName": fileName,
78
- })
79
- s.sse.Broadcast(string(event))
80
-
81
- writeJSON(w, http.StatusOK, map[string]string{
82
- "path": absPath,
83
- "fileName": fileName,
84
- "status": "added",
85
- })
86
- }
87
-
88
- func (s *Server) getDocument(w http.ResponseWriter, r *http.Request) {
89
- path := s.resolveFilePath(r)
90
-
91
- s.mu.RLock()
92
- state := s.files[path]
93
- clean := s.clean
94
- s.mu.RUnlock()
95
-
96
- if state == nil {
97
- writeError(w, http.StatusNotFound, "document not found")
98
- return
99
- }
100
-
101
- writeJSON(w, http.StatusOK, map[string]any{
102
- "html": state.RenderedHTML,
103
- "headings": state.Headings,
104
- "filePath": state.FilePath,
105
- "fileName": state.FileName,
106
- "clean": clean,
107
- })
108
- }
109
-
110
- func isMarkdownFile(path string) bool {
111
- ext := strings.ToLower(filepath.Ext(path))
112
- return ext == ".md" || ext == ".markdown"
113
- }
@@ -1,17 +0,0 @@
1
- package server
2
-
3
- import (
4
- "embed"
5
- "io/fs"
6
- )
7
-
8
- //go:embed all:dist
9
- var embeddedAssets embed.FS
10
-
11
- func EmbeddedAssetsFS() fs.FS {
12
- sub, err := fs.Sub(embeddedAssets, "dist")
13
- if err != nil {
14
- return nil
15
- }
16
- return sub
17
- }
@@ -1,33 +0,0 @@
1
- package server
2
-
3
- import (
4
- "bytes"
5
- "strings"
6
-
7
- "github.com/yuin/goldmark"
8
- "github.com/yuin/goldmark/ast"
9
- "github.com/yuin/goldmark/parser"
10
- "github.com/yuin/goldmark/text"
11
- )
12
-
13
- // ExtractHeadings parses markdown source and returns headings using goldmark's AST.
14
- // This ensures heading IDs match exactly what goldmark renders in HTML.
15
- func ExtractHeadings(source []byte) []Heading {
16
- md := goldmark.New(
17
- goldmark.WithParserOptions(
18
- parser.WithAutoHeadingID(),
19
- ),
20
- )
21
-
22
- reader := text.NewReader(source)
23
- doc := md.Parser().Parse(reader)
24
-
25
- return extractHeadingsFromAST(doc, source)
26
- }
27
-
28
- // collectHeadingText recursively collects plain text from heading AST nodes.
29
- func collectHeadingText(n ast.Node, source []byte) string {
30
- var buf bytes.Buffer
31
- collectText(n, source, &buf)
32
- return strings.TrimSpace(buf.String())
33
- }
@@ -1,75 +0,0 @@
1
- package server
2
-
3
- import "testing"
4
-
5
- func TestExtractHeadingsDeduplicate(t *testing.T) {
6
- src := []byte("# Title\n\n## Title\n\n### Title\n")
7
- headings := ExtractHeadings(src)
8
-
9
- if len(headings) != 3 {
10
- t.Fatalf("expected 3 headings, got %d", len(headings))
11
- }
12
-
13
- if headings[0].ID != "title" {
14
- t.Errorf("heading 0 ID = %q, want %q", headings[0].ID, "title")
15
- }
16
- if headings[1].ID != "title-1" {
17
- t.Errorf("heading 1 ID = %q, want %q", headings[1].ID, "title-1")
18
- }
19
- if headings[2].ID != "title-2" {
20
- t.Errorf("heading 2 ID = %q, want %q", headings[2].ID, "title-2")
21
- }
22
- }
23
-
24
- func TestExtractHeadingsSkipsCodeBlocks(t *testing.T) {
25
- src := []byte("# Real Heading\n\n```\n# Not a heading\n```\n\n## Another Real\n")
26
- headings := ExtractHeadings(src)
27
-
28
- if len(headings) != 2 {
29
- t.Fatalf("expected 2 headings, got %d", len(headings))
30
- }
31
-
32
- if headings[0].Text != "Real Heading" {
33
- t.Errorf("heading 0 text = %q", headings[0].Text)
34
- }
35
- if headings[1].Text != "Another Real" {
36
- t.Errorf("heading 1 text = %q", headings[1].Text)
37
- }
38
- }
39
-
40
- func TestExtractHeadingsLevels(t *testing.T) {
41
- src := []byte("# H1\n## H2\n### H3\n#### H4\n##### H5\n###### H6\n")
42
- headings := ExtractHeadings(src)
43
-
44
- if len(headings) != 6 {
45
- t.Fatalf("expected 6 headings, got %d", len(headings))
46
- }
47
-
48
- for i, h := range headings {
49
- if h.Level != i+1 {
50
- t.Errorf("heading %d level = %d, want %d", i, h.Level, i+1)
51
- }
52
- }
53
- }
54
-
55
- func TestExtractHeadingsSetextStyle(t *testing.T) {
56
- src := []byte("Setext H1\n=========\n\nSetext H2\n---------\n")
57
- headings := ExtractHeadings(src)
58
-
59
- if len(headings) != 2 {
60
- t.Fatalf("expected 2 headings, got %d", len(headings))
61
- }
62
-
63
- if headings[0].Text != "Setext H1" {
64
- t.Errorf("heading 0 text = %q, want %q", headings[0].Text, "Setext H1")
65
- }
66
- if headings[0].Level != 1 {
67
- t.Errorf("heading 0 level = %d, want 1", headings[0].Level)
68
- }
69
- if headings[1].Text != "Setext H2" {
70
- t.Errorf("heading 1 text = %q, want %q", headings[1].Text, "Setext H2")
71
- }
72
- if headings[1].Level != 2 {
73
- t.Errorf("heading 1 level = %d, want 2", headings[1].Level)
74
- }
75
- }