shelving 1.234.1 → 1.236.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 (347) hide show
  1. package/extract/DirectoryExtractor.d.ts +5 -5
  2. package/extract/DirectoryExtractor.js +3 -3
  3. package/extract/Extractor.d.ts +1 -1
  4. package/extract/FileExtractor.d.ts +4 -4
  5. package/extract/FileExtractor.js +1 -1
  6. package/extract/IndexExtractor.d.ts +24 -0
  7. package/extract/IndexExtractor.js +50 -0
  8. package/extract/MarkupExtractor.d.ts +2 -2
  9. package/extract/MergingExtractor.d.ts +7 -7
  10. package/extract/MergingExtractor.js +10 -8
  11. package/extract/ModuleExtractor.d.ts +5 -5
  12. package/extract/ModuleExtractor.js +2 -2
  13. package/extract/PackageExtractor.d.ts +15 -11
  14. package/extract/PackageExtractor.js +45 -36
  15. package/extract/ThroughExtractor.d.ts +1 -1
  16. package/extract/TypescriptExtractor.d.ts +7 -3
  17. package/extract/TypescriptExtractor.js +188 -34
  18. package/extract/index.d.ts +1 -1
  19. package/extract/index.js +1 -1
  20. package/markup/rule/fenced.js +1 -1
  21. package/markup/rule/table.js +1 -1
  22. package/package.json +5 -5
  23. package/schema/ChoiceSchema.d.ts +9 -9
  24. package/schema/CountrySchema.d.ts +6 -6
  25. package/schema/CountrySchema.js +3 -10
  26. package/ui/README.md +104 -135
  27. package/ui/block/Address.d.ts +5 -4
  28. package/ui/block/Address.js +8 -5
  29. package/ui/block/Address.module.css +4 -6
  30. package/ui/block/Address.tsx +13 -10
  31. package/ui/block/Block.d.ts +6 -23
  32. package/ui/block/Block.js +7 -39
  33. package/ui/block/Block.module.css +3 -72
  34. package/ui/block/Block.tsx +17 -71
  35. package/ui/block/Blockquote.d.ts +5 -5
  36. package/ui/block/Blockquote.js +7 -6
  37. package/ui/block/Blockquote.module.css +12 -3
  38. package/ui/block/Blockquote.tsx +11 -18
  39. package/ui/block/Caption.d.ts +11 -0
  40. package/ui/block/Caption.js +13 -0
  41. package/ui/block/Caption.module.css +39 -0
  42. package/ui/block/Caption.tsx +28 -0
  43. package/ui/block/Card.d.ts +5 -8
  44. package/ui/block/Card.js +4 -5
  45. package/ui/block/Card.module.css +25 -33
  46. package/ui/block/Card.tsx +9 -14
  47. package/ui/block/Definitions.d.ts +8 -26
  48. package/ui/block/Definitions.js +10 -23
  49. package/ui/block/Definitions.module.css +24 -34
  50. package/ui/block/Definitions.tsx +15 -51
  51. package/ui/block/Divider.d.ts +6 -4
  52. package/ui/block/Divider.js +7 -4
  53. package/ui/block/Divider.module.css +4 -2
  54. package/ui/block/Divider.tsx +16 -5
  55. package/ui/block/Heading.d.ts +5 -4
  56. package/ui/block/Heading.js +7 -5
  57. package/ui/block/Heading.module.css +9 -7
  58. package/ui/block/Heading.tsx +11 -10
  59. package/ui/block/Image.d.ts +4 -2
  60. package/ui/block/Image.js +4 -2
  61. package/ui/block/Image.module.css +1 -1
  62. package/ui/block/Image.tsx +6 -5
  63. package/ui/block/Label.d.ts +11 -0
  64. package/ui/block/Label.js +17 -0
  65. package/ui/block/Label.module.css +32 -0
  66. package/ui/block/Label.tsx +32 -0
  67. package/ui/block/List.d.ts +6 -3
  68. package/ui/block/List.js +7 -4
  69. package/ui/block/List.module.css +11 -2
  70. package/ui/block/List.tsx +13 -9
  71. package/ui/block/Panel.d.ts +6 -12
  72. package/ui/block/Panel.js +7 -8
  73. package/ui/block/Panel.module.css +21 -14
  74. package/ui/block/Panel.tsx +12 -20
  75. package/ui/block/Paragraph.d.ts +4 -5
  76. package/ui/block/Paragraph.js +5 -5
  77. package/ui/block/Paragraph.module.css +5 -6
  78. package/ui/block/Paragraph.tsx +8 -10
  79. package/ui/block/Preformatted.d.ts +12 -5
  80. package/ui/block/Preformatted.js +12 -4
  81. package/ui/block/Preformatted.module.css +38 -22
  82. package/ui/block/Preformatted.tsx +34 -7
  83. package/ui/block/Prose.js +25 -23
  84. package/ui/block/Prose.module.css +1 -1
  85. package/ui/block/Prose.tsx +48 -44
  86. package/ui/block/README.md +41 -14
  87. package/ui/block/Section.d.ts +24 -0
  88. package/ui/block/Section.js +36 -0
  89. package/ui/block/Section.module.css +20 -0
  90. package/ui/block/Section.tsx +66 -0
  91. package/ui/block/Subheading.d.ts +3 -1
  92. package/ui/block/Subheading.js +7 -5
  93. package/ui/block/Subheading.module.css +10 -6
  94. package/ui/block/Subheading.tsx +10 -9
  95. package/ui/block/Table.d.ts +7 -7
  96. package/ui/block/Table.js +9 -8
  97. package/ui/block/Table.module.css +12 -6
  98. package/ui/block/Table.tsx +13 -14
  99. package/ui/block/Title.d.ts +3 -1
  100. package/ui/block/Title.js +7 -5
  101. package/ui/block/Title.module.css +10 -6
  102. package/ui/block/Title.tsx +10 -9
  103. package/ui/block/Video.d.ts +3 -3
  104. package/ui/block/Video.js +2 -2
  105. package/ui/block/Video.module.css +41 -55
  106. package/ui/block/Video.tsx +3 -3
  107. package/ui/block/index.d.ts +1 -0
  108. package/ui/block/index.js +1 -0
  109. package/ui/block/index.ts +1 -0
  110. package/ui/dialog/Dialog.d.ts +1 -1
  111. package/ui/dialog/Dialog.module.css +1 -1
  112. package/ui/dialog/Modal.module.css +8 -4
  113. package/ui/docs/DocumentationButtons.d.ts +15 -0
  114. package/ui/docs/DocumentationButtons.js +30 -0
  115. package/ui/docs/DocumentationButtons.tsx +52 -0
  116. package/ui/docs/DocumentationCard.d.ts +7 -8
  117. package/ui/docs/DocumentationCard.js +13 -8
  118. package/ui/docs/DocumentationCard.tsx +28 -20
  119. package/ui/docs/DocumentationKind.d.ts +5 -4
  120. package/ui/docs/DocumentationKind.js +2 -3
  121. package/ui/docs/DocumentationKind.tsx +11 -8
  122. package/ui/docs/DocumentationPage.d.ts +5 -11
  123. package/ui/docs/DocumentationPage.js +29 -22
  124. package/ui/docs/DocumentationPage.test.tsx +12 -3
  125. package/ui/docs/DocumentationPage.tsx +117 -100
  126. package/ui/docs/DocumentationSignatures.d.ts +14 -0
  127. package/ui/docs/DocumentationSignatures.js +13 -0
  128. package/ui/docs/DocumentationSignatures.tsx +24 -0
  129. package/ui/docs/README.md +17 -11
  130. package/ui/docs/index.d.ts +2 -4
  131. package/ui/docs/index.js +2 -4
  132. package/ui/docs/index.ts +2 -4
  133. package/ui/form/ArrayInput.js +4 -4
  134. package/ui/form/ArrayInput.tsx +7 -7
  135. package/ui/form/ArrayRadioInputs.js +2 -2
  136. package/ui/form/ArrayRadioInputs.tsx +3 -3
  137. package/ui/form/Button.d.ts +11 -9
  138. package/ui/form/Button.js +9 -5
  139. package/ui/form/Button.module.css +44 -42
  140. package/ui/form/Button.tsx +18 -15
  141. package/ui/form/ChoiceRadioInputs.js +2 -2
  142. package/ui/form/ChoiceRadioInputs.tsx +3 -3
  143. package/ui/form/Clickable.d.ts +4 -2
  144. package/ui/form/Clickable.js +16 -9
  145. package/ui/form/Clickable.tsx +52 -11
  146. package/ui/form/DataInput.js +2 -2
  147. package/ui/form/DataInput.tsx +3 -3
  148. package/ui/form/DictionaryInput.js +4 -4
  149. package/ui/form/DictionaryInput.tsx +7 -7
  150. package/ui/form/Field.d.ts +3 -1
  151. package/ui/form/Field.js +3 -2
  152. package/ui/form/Field.module.css +10 -6
  153. package/ui/form/Field.tsx +5 -2
  154. package/ui/form/Form.module.css +1 -1
  155. package/ui/form/FormFooter.js +3 -3
  156. package/ui/form/FormFooter.tsx +4 -4
  157. package/ui/form/Input.d.ts +1 -1
  158. package/ui/form/Input.module.css +34 -44
  159. package/ui/form/Popover.module.css +8 -4
  160. package/ui/form/Progress.module.css +7 -7
  161. package/ui/form/RadioInput.d.ts +2 -2
  162. package/ui/form/RadioInput.tsx +2 -2
  163. package/ui/form/SubmitButton.d.ts +2 -2
  164. package/ui/form/SubmitButton.js +3 -3
  165. package/ui/form/SubmitButton.tsx +9 -3
  166. package/ui/inline/Code.d.ts +10 -13
  167. package/ui/inline/Code.js +9 -14
  168. package/ui/inline/Code.module.css +10 -15
  169. package/ui/inline/Code.tsx +24 -26
  170. package/ui/inline/Deleted.d.ts +2 -0
  171. package/ui/inline/Deleted.js +5 -2
  172. package/ui/inline/Deleted.module.css +2 -2
  173. package/ui/inline/Deleted.tsx +6 -2
  174. package/ui/inline/Emphasis.d.ts +2 -0
  175. package/ui/inline/Emphasis.js +5 -2
  176. package/ui/inline/Emphasis.tsx +6 -2
  177. package/ui/inline/Inserted.d.ts +2 -0
  178. package/ui/inline/Inserted.js +5 -2
  179. package/ui/inline/Inserted.module.css +2 -2
  180. package/ui/inline/Inserted.tsx +6 -2
  181. package/ui/inline/Link.d.ts +2 -0
  182. package/ui/inline/Link.js +5 -2
  183. package/ui/inline/Link.module.css +2 -1
  184. package/ui/inline/Link.tsx +6 -2
  185. package/ui/inline/Mark.d.ts +2 -0
  186. package/ui/inline/Mark.js +5 -2
  187. package/ui/inline/Mark.tsx +6 -2
  188. package/ui/inline/Small.d.ts +2 -0
  189. package/ui/inline/Small.js +5 -2
  190. package/ui/inline/Small.tsx +6 -2
  191. package/ui/inline/Strong.d.ts +2 -0
  192. package/ui/inline/Strong.js +5 -2
  193. package/ui/inline/Strong.tsx +6 -2
  194. package/ui/inline/Subscript.d.ts +2 -0
  195. package/ui/inline/Subscript.js +5 -2
  196. package/ui/inline/Subscript.tsx +6 -2
  197. package/ui/inline/Superscript.d.ts +2 -0
  198. package/ui/inline/Superscript.js +5 -2
  199. package/ui/inline/Superscript.tsx +6 -2
  200. package/ui/layout/Layout.module.css +17 -12
  201. package/ui/layout/README.md +1 -1
  202. package/ui/layout/SidebarLayout.js +1 -1
  203. package/ui/layout/SidebarLayout.module.css +34 -17
  204. package/ui/layout/SidebarLayout.tsx +1 -1
  205. package/ui/menu/Menu.d.ts +14 -0
  206. package/ui/menu/Menu.js +26 -3
  207. package/ui/menu/Menu.module.css +31 -31
  208. package/ui/menu/Menu.tsx +49 -2
  209. package/ui/menu/index.d.ts +0 -1
  210. package/ui/menu/index.js +0 -1
  211. package/ui/menu/index.ts +0 -1
  212. package/ui/misc/Catcher.js +3 -3
  213. package/ui/misc/Catcher.tsx +5 -5
  214. package/ui/misc/Loading.d.ts +1 -1
  215. package/ui/misc/Loading.module.css +2 -2
  216. package/ui/misc/Mapper.d.ts +2 -4
  217. package/ui/misc/Mapper.js +2 -4
  218. package/ui/misc/Mapper.tsx +2 -4
  219. package/ui/misc/README.md +11 -12
  220. package/ui/misc/StatusIcon.d.ts +3 -6
  221. package/ui/misc/StatusIcon.js +2 -2
  222. package/ui/misc/StatusIcon.tsx +4 -7
  223. package/ui/misc/Tag.d.ts +5 -7
  224. package/ui/misc/Tag.js +8 -6
  225. package/ui/misc/Tag.module.css +21 -27
  226. package/ui/misc/Tag.tsx +14 -15
  227. package/ui/notice/Message.d.ts +5 -6
  228. package/ui/notice/Message.js +4 -2
  229. package/ui/notice/Message.module.css +5 -2
  230. package/ui/notice/Message.tsx +9 -9
  231. package/ui/notice/Notice.d.ts +5 -6
  232. package/ui/notice/Notice.js +4 -3
  233. package/ui/notice/Notice.module.css +16 -12
  234. package/ui/notice/Notice.tsx +11 -13
  235. package/ui/notice/Notices.js +3 -2
  236. package/ui/notice/Notices.tsx +4 -2
  237. package/ui/notice/NoticesStore.d.ts +1 -1
  238. package/ui/style/Color.d.ts +13 -29
  239. package/ui/style/Color.js +12 -4
  240. package/ui/style/Color.module.css +14 -40
  241. package/ui/style/Color.tsx +29 -32
  242. package/ui/style/Flex.d.ts +58 -16
  243. package/ui/style/Flex.js +10 -10
  244. package/ui/style/Flex.module.css +50 -26
  245. package/ui/style/Flex.tsx +63 -18
  246. package/ui/style/Gap.d.ts +7 -11
  247. package/ui/style/Gap.js +3 -2
  248. package/ui/style/Gap.module.css +9 -10
  249. package/ui/style/Gap.tsx +9 -13
  250. package/ui/style/Padding.d.ts +7 -15
  251. package/ui/style/Padding.js +3 -2
  252. package/ui/style/Padding.module.css +9 -11
  253. package/ui/style/Padding.tsx +9 -17
  254. package/ui/style/Scroll.d.ts +16 -0
  255. package/ui/style/Scroll.js +13 -0
  256. package/ui/style/Scroll.module.css +38 -0
  257. package/ui/style/Scroll.tsx +29 -0
  258. package/ui/style/Space.d.ts +9 -0
  259. package/ui/style/Space.js +6 -0
  260. package/ui/style/{Spacing.module.css → Space.module.css} +9 -9
  261. package/ui/style/Space.tsx +16 -0
  262. package/ui/style/Status.d.ts +15 -17
  263. package/ui/style/Status.js +14 -4
  264. package/ui/style/Status.module.css +9 -17
  265. package/ui/style/Status.tsx +20 -20
  266. package/ui/style/Tint.d.ts +2 -0
  267. package/ui/style/Tint.js +4 -0
  268. package/ui/style/Tint.module.css +44 -0
  269. package/ui/style/Tint.tsx +5 -0
  270. package/ui/style/Typography.d.ts +28 -40
  271. package/ui/style/Typography.js +2 -2
  272. package/ui/style/Typography.module.css +102 -28
  273. package/ui/style/Typography.tsx +52 -41
  274. package/ui/style/Width.d.ts +2 -2
  275. package/ui/style/Width.module.css +17 -7
  276. package/ui/style/Width.tsx +2 -2
  277. package/ui/style/base.css +51 -111
  278. package/ui/style/index.d.ts +3 -3
  279. package/ui/style/index.js +3 -3
  280. package/ui/style/index.tsx +3 -3
  281. package/ui/tree/README.md +12 -8
  282. package/ui/tree/TreeBreadcrumbs.d.ts +15 -0
  283. package/ui/tree/TreeBreadcrumbs.js +28 -0
  284. package/ui/tree/TreeBreadcrumbs.tsx +48 -0
  285. package/ui/tree/TreeButton.d.ts +18 -0
  286. package/ui/tree/TreeButton.js +17 -0
  287. package/ui/tree/TreeButton.test.tsx +63 -0
  288. package/ui/tree/TreeButton.tsx +30 -0
  289. package/ui/tree/TreeCard.d.ts +4 -0
  290. package/ui/tree/TreeCard.js +9 -0
  291. package/ui/tree/TreeCard.tsx +16 -0
  292. package/ui/tree/TreeCards.d.ts +6 -13
  293. package/ui/tree/TreeCards.js +5 -8
  294. package/ui/tree/TreeCards.tsx +8 -19
  295. package/ui/tree/TreeContext.d.ts +18 -0
  296. package/ui/tree/TreeContext.js +23 -0
  297. package/ui/tree/TreeContext.tsx +25 -0
  298. package/ui/tree/TreeMenu.d.ts +4 -3
  299. package/ui/tree/TreeMenu.js +5 -7
  300. package/ui/tree/TreeMenu.tsx +7 -8
  301. package/ui/tree/TreePage.d.ts +8 -0
  302. package/ui/tree/TreePage.js +15 -0
  303. package/ui/tree/TreePage.tsx +33 -0
  304. package/ui/tree/TreeRouter.d.ts +8 -13
  305. package/ui/tree/TreeRouter.js +17 -16
  306. package/ui/tree/TreeRouter.test.tsx +4 -4
  307. package/ui/tree/TreeRouter.tsx +24 -24
  308. package/ui/tree/TreeSidebar.d.ts +1 -1
  309. package/ui/tree/TreeSidebar.js +1 -2
  310. package/ui/tree/TreeSidebar.tsx +3 -3
  311. package/ui/tree/index.d.ts +5 -0
  312. package/ui/tree/index.js +5 -0
  313. package/ui/tree/index.ts +5 -0
  314. package/util/element.d.ts +1 -175
  315. package/util/element.js +1 -77
  316. package/util/index.d.ts +1 -0
  317. package/util/index.js +1 -0
  318. package/util/tree.d.ts +132 -0
  319. package/util/tree.js +33 -0
  320. package/extract/IndexFileExtractor.d.ts +0 -24
  321. package/extract/IndexFileExtractor.js +0 -48
  322. package/ui/docs/DirectoryCard.d.ts +0 -9
  323. package/ui/docs/DirectoryCard.js +0 -10
  324. package/ui/docs/DirectoryCard.tsx +0 -21
  325. package/ui/docs/DirectoryPage.d.ts +0 -10
  326. package/ui/docs/DirectoryPage.js +0 -13
  327. package/ui/docs/DirectoryPage.tsx +0 -35
  328. package/ui/docs/FileCard.d.ts +0 -9
  329. package/ui/docs/FileCard.js +0 -10
  330. package/ui/docs/FileCard.tsx +0 -21
  331. package/ui/docs/FilePage.d.ts +0 -10
  332. package/ui/docs/FilePage.js +0 -10
  333. package/ui/docs/FilePage.tsx +0 -28
  334. package/ui/menu/MenuItem.d.ts +0 -15
  335. package/ui/menu/MenuItem.js +0 -18
  336. package/ui/menu/MenuItem.tsx +0 -34
  337. package/ui/style/Align.d.ts +0 -13
  338. package/ui/style/Align.js +0 -6
  339. package/ui/style/Align.module.css +0 -17
  340. package/ui/style/Align.tsx +0 -20
  341. package/ui/style/Spacing.d.ts +0 -15
  342. package/ui/style/Spacing.js +0 -6
  343. package/ui/style/Spacing.tsx +0 -22
  344. package/ui/style/Thickness.d.ts +0 -19
  345. package/ui/style/Thickness.js +0 -5
  346. package/ui/style/Thickness.module.css +0 -35
  347. package/ui/style/Thickness.tsx +0 -26
@@ -1,6 +1,6 @@
1
1
  import type { ImmutableDictionary } from "../util/dictionary.js";
2
- import type { DirectoryElement } from "../util/element.js";
3
2
  import { type AbsolutePath, type Matchables, type Path } from "../util/index.js";
3
+ import type { TreeElement } from "../util/tree.js";
4
4
  import { Extractor } from "./Extractor.js";
5
5
  import { FileExtractor } from "./FileExtractor.js";
6
6
  /** Options for a directory extractor. */
@@ -21,19 +21,19 @@ export interface DirectoryExtractorOptions {
21
21
  readonly ignore?: Matchables;
22
22
  }
23
23
  /**
24
- * Extractor that walks a directory on disk and produces a `DirectoryElement` tree.
24
+ * Extractor that walks a directory on disk and produces a tree of `tree-element` nodes.
25
25
  * - Recursively descends into subdirectories.
26
26
  * - Dispatches non-ignored files to a matching `FileExtractor` based on extension; files with no matching extractor are silently skipped.
27
27
  * - Keys on the produced elements are the verbatim filenames (e.g. `"string.ts"`, `"README.md"`) and directory names (e.g. `"util"`).
28
28
  * - This is a pure walker: same-key merging and README absorption are intentionally *not* applied here — wrap with `MergingExtractor`
29
- * and/or `IndexFileExtractor` to opt in to those behaviours.
29
+ * and/or `IndexExtractor` to opt in to those behaviours.
30
30
  */
31
- export declare class DirectoryExtractor extends Extractor<Path, DirectoryElement> {
31
+ export declare class DirectoryExtractor extends Extractor<Path, TreeElement> {
32
32
  private readonly _extractors;
33
33
  private readonly _base;
34
34
  private readonly _ignore;
35
35
  constructor({ extractors, base, ignore }?: DirectoryExtractorOptions);
36
- extract(source: Path): Promise<DirectoryElement>;
36
+ extract(source: Path): Promise<TreeElement>;
37
37
  private _extractDirectory;
38
38
  private _extractChild;
39
39
  }
@@ -20,12 +20,12 @@ const DEFAULT_EXTRACTORS = {
20
20
  */
21
21
  const DEFAULT_IGNORE = [/\.test\.tsx?$/i, /\.spec\.tsx?$/i, /^node_modules$/i, /^[_.]/i];
22
22
  /**
23
- * Extractor that walks a directory on disk and produces a `DirectoryElement` tree.
23
+ * Extractor that walks a directory on disk and produces a tree of `tree-element` nodes.
24
24
  * - Recursively descends into subdirectories.
25
25
  * - Dispatches non-ignored files to a matching `FileExtractor` based on extension; files with no matching extractor are silently skipped.
26
26
  * - Keys on the produced elements are the verbatim filenames (e.g. `"string.ts"`, `"README.md"`) and directory names (e.g. `"util"`).
27
27
  * - This is a pure walker: same-key merging and README absorption are intentionally *not* applied here — wrap with `MergingExtractor`
28
- * and/or `IndexFileExtractor` to opt in to those behaviours.
28
+ * and/or `IndexExtractor` to opt in to those behaviours.
29
29
  */
30
30
  export class DirectoryExtractor extends Extractor {
31
31
  _extractors;
@@ -52,7 +52,7 @@ export class DirectoryExtractor extends Extractor {
52
52
  children.push(child);
53
53
  }
54
54
  return {
55
- type: "tree-directory",
55
+ type: "tree-element",
56
56
  key: name,
57
57
  props: {
58
58
  source,
@@ -1,4 +1,4 @@
1
- import { type TreeElement } from "../util/element.js";
1
+ import type { TreeElement } from "../util/tree.js";
2
2
  /**
3
3
  * Base class for an extractor that converts input into a tree element.
4
4
  * - Extractors are composable: outer extractors delegate to inner extractors.
@@ -1,5 +1,5 @@
1
1
  import type { BunFile } from "bun";
2
- import type { FileElement, FileElementProps } from "../util/element.js";
2
+ import type { TreeElement, TreeElementProps } from "../util/tree.js";
3
3
  import { Extractor } from "./Extractor.js";
4
4
  /**
5
5
  * Base extractor for a file in a tree.
@@ -11,15 +11,15 @@ import { Extractor } from "./Extractor.js";
11
11
  * - Does NOT set `title` — `title` is only set by subclasses that have a confident source for one (e.g. `MarkupExtractor` uses the first `<h1>`). Renderers fall back to `name` when missing.
12
12
  * - Subclasses (e.g. `MarkupExtractor`, `TypescriptExtractor`) override `extractProps()` to parse the content into richer elements.
13
13
  */
14
- export declare class FileExtractor extends Extractor<BunFile, FileElement> {
15
- extract(file: BunFile): Promise<FileElement>;
14
+ export declare class FileExtractor extends Extractor<BunFile, TreeElement> {
15
+ extract(file: BunFile): Promise<TreeElement>;
16
16
  /**
17
17
  * Build the file element props from the extracted content.
18
18
  * - `name` is the basename without extension (e.g. `"array"`) — display-ready, used by menus, cards, and URL paths.
19
19
  * - Override to parse `text` into richer elements (content/children/description) and to set
20
20
  * `title` if a confident title is available.
21
21
  */
22
- extractProps(name: string, content: string): Partial<FileElementProps> & {
22
+ extractProps(name: string, content: string): Partial<TreeElementProps> & {
23
23
  name: string;
24
24
  };
25
25
  }
@@ -22,7 +22,7 @@ export class FileExtractor extends Extractor {
22
22
  const text = await file.text();
23
23
  const props = { ...this.extractProps(base, text), source };
24
24
  return {
25
- type: "tree-file",
25
+ type: "tree-element",
26
26
  key: filename,
27
27
  props,
28
28
  };
@@ -0,0 +1,24 @@
1
+ import { type Matchables } from "../util/regexp.js";
2
+ import type { TreeElement } from "../util/tree.js";
3
+ import type { Extractor } from "./Extractor.js";
4
+ import { ThroughExtractor } from "./ThroughExtractor.js";
5
+ /** Options for an `IndexExtractor`. */
6
+ export interface IndexExtractorOptions {
7
+ /**
8
+ * Filename patterns treated as a parent's index. Matched case-insensitively against each child element's `key`.
9
+ * - Defaults to README and index files: `["readme.txt", "readme.md", "index.md", "index.ts", "index.tsx"]`.
10
+ */
11
+ readonly index?: Matchables;
12
+ }
13
+ /**
14
+ * Through extractor that absorbs each element's index child into the element itself.
15
+ * - For every element with children: finds the first child whose `key` matches any `index` pattern.
16
+ * - The matched child's `title`, `description`, `content`, and `children` are folded into the parent.
17
+ * - The matched child is removed from the parent's children list.
18
+ * - Purely name-based: it doesn't care whether an element is a directory or a file — any element with children is processed, deepest level first.
19
+ */
20
+ export declare class IndexExtractor<I> extends ThroughExtractor<I, TreeElement> {
21
+ private readonly _index;
22
+ constructor(source: Extractor<I, TreeElement>, { index }?: IndexExtractorOptions);
23
+ extract(input: I): Promise<TreeElement>;
24
+ }
@@ -0,0 +1,50 @@
1
+ import { mergeElements, walkElements } from "../util/element.js";
2
+ import { notNullish } from "../util/null.js";
3
+ import { anyMatch } from "../util/regexp.js";
4
+ import { ThroughExtractor } from "./ThroughExtractor.js";
5
+ /**
6
+ * Default index file patterns.
7
+ * - Matched case-insensitively (all entries stored lowercase).
8
+ * - The first child that matches any pattern is absorbed.
9
+ */
10
+ const DEFAULT_INDEX = [/^readme\.txt$/i, /^readme\.md$/i, /^index\.md$/i, /^index\.ts$/i, /^index\.tsx$/i];
11
+ /**
12
+ * Through extractor that absorbs each element's index child into the element itself.
13
+ * - For every element with children: finds the first child whose `key` matches any `index` pattern.
14
+ * - The matched child's `title`, `description`, `content`, and `children` are folded into the parent.
15
+ * - The matched child is removed from the parent's children list.
16
+ * - Purely name-based: it doesn't care whether an element is a directory or a file — any element with children is processed, deepest level first.
17
+ */
18
+ export class IndexExtractor extends ThroughExtractor {
19
+ _index;
20
+ constructor(source, { index = DEFAULT_INDEX } = {}) {
21
+ super(source);
22
+ this._index = index;
23
+ }
24
+ async extract(input) {
25
+ const root = await this.source.extract(input);
26
+ return _absorbIndex(root, this._index);
27
+ }
28
+ }
29
+ /** Recursively absorb the index child in `element` and all of its descendants that have children. */
30
+ function _absorbIndex(element, index) {
31
+ // Recurse first so nested levels absorb their own indexes before we look at this one.
32
+ // Only descend into elements that actually have children — leaving childless leaves (e.g. files) untouched, including their `undefined` children.
33
+ const recursed = Array.from(walkElements(element.props.children)).map(child => notNullish(child.props.children) ? _absorbIndex(child, index) : child);
34
+ // Find the index child by key.
35
+ const indexChild = recursed.find(child => anyMatch(child.key, ...index));
36
+ if (!indexChild)
37
+ return { ...element, props: { ...element.props, children: recursed } };
38
+ // Fold the index child into the parent, and drop it from children.
39
+ const remaining = recursed.filter(child => child !== indexChild);
40
+ return {
41
+ ...element,
42
+ props: {
43
+ ...element.props,
44
+ title: element.props.title ?? indexChild.props.title,
45
+ description: element.props.description ?? indexChild.props.description,
46
+ content: element.props.content ?? indexChild.props.content,
47
+ children: mergeElements(indexChild.props.children, remaining),
48
+ },
49
+ };
50
+ }
@@ -1,4 +1,4 @@
1
- import { type FileElementProps } from "../util/element.js";
1
+ import type { TreeElementProps } from "../util/tree.js";
2
2
  import { FileExtractor } from "./FileExtractor.js";
3
3
  /**
4
4
  * File extractor for Markdown files.
@@ -10,7 +10,7 @@ import { FileExtractor } from "./FileExtractor.js";
10
10
  * - Sets `description` to the first prose paragraph as a plain-text summary (used for card listings and `<meta>`).
11
11
  */
12
12
  export declare class MarkupExtractor extends FileExtractor {
13
- extractProps(name: string, text: string): Partial<FileElementProps> & {
13
+ extractProps(name: string, text: string): Partial<TreeElementProps> & {
14
14
  name: string;
15
15
  };
16
16
  }
@@ -1,5 +1,5 @@
1
1
  import type { ImmutableDictionary } from "../util/dictionary.js";
2
- import { type DirectoryElement } from "../util/element.js";
2
+ import type { TreeElement } from "../util/tree.js";
3
3
  import type { Extractor } from "./Extractor.js";
4
4
  import { ThroughExtractor } from "./ThroughExtractor.js";
5
5
  /** Options for a `MergingExtractor`. */
@@ -8,20 +8,20 @@ export interface MergingExtractorOptions {
8
8
  * Templated key pairs that should merge. Each key is a `{base}` template matched against the secondary element's key;
9
9
  * each value is an ordered list of `{base}` templates for the primary candidates to merge into.
10
10
  * - The first primary candidate that exists in the same directory wins; remaining candidates are ignored.
11
- * - If no candidate exists the secondary is left in place as its own tree-file element.
11
+ * - If no candidate exists the secondary is left in place as its own tree element.
12
12
  * - Defaults to `{ "{base}.md": ["{base}.ts", "{base}.tsx", "{base}.js", "{base}.jsx"] }`.
13
13
  */
14
14
  readonly merges?: ImmutableDictionary<readonly string[]>;
15
15
  }
16
16
  /**
17
- * Through extractor that walks a `DirectoryElement` tree and merges sibling tree elements whose keys match a `merges` template pair.
18
- * - Walks every directory recursively, applying the merge at each level.
17
+ * Through extractor that walks a tree of `tree-element` nodes and merges sibling tree elements whose keys match a `merges` template pair.
18
+ * - Purely key-based: it doesn't care whether siblings are directories or files — any element with children is processed, at every level.
19
19
  * - The primary (winning) element keeps its `key`, `source`, and `type`; the secondary's `title`, `description`,
20
20
  * `content`, and `children` are folded in via `mergeTreeElements()`.
21
21
  * - A secondary with no matching primary is left in place — pure prose files (e.g. `concepts.md` with no `concepts.ts`) stand alone.
22
22
  */
23
- export declare class MergingExtractor<I> extends ThroughExtractor<I, DirectoryElement> {
23
+ export declare class MergingExtractor<I> extends ThroughExtractor<I, TreeElement> {
24
24
  private readonly _merges;
25
- constructor(source: Extractor<I, DirectoryElement>, { merges }?: MergingExtractorOptions);
26
- extract(input: I): Promise<DirectoryElement>;
25
+ constructor(source: Extractor<I, TreeElement>, { merges }?: MergingExtractorOptions);
26
+ extract(input: I): Promise<TreeElement>;
27
27
  }
@@ -1,4 +1,5 @@
1
1
  import { walkElements } from "../util/element.js";
2
+ import { notNullish } from "../util/null.js";
2
3
  import { matchTemplate, renderTemplate } from "../util/template.js";
3
4
  import { mergeTreeElements } from "./Extractor.js";
4
5
  import { ThroughExtractor } from "./ThroughExtractor.js";
@@ -12,8 +13,8 @@ const DEFAULT_MERGES = {
12
13
  "{base}.md": ["{base}.ts", "{base}.tsx", "{base}.js", "{base}.jsx"],
13
14
  };
14
15
  /**
15
- * Through extractor that walks a `DirectoryElement` tree and merges sibling tree elements whose keys match a `merges` template pair.
16
- * - Walks every directory recursively, applying the merge at each level.
16
+ * Through extractor that walks a tree of `tree-element` nodes and merges sibling tree elements whose keys match a `merges` template pair.
17
+ * - Purely key-based: it doesn't care whether siblings are directories or files — any element with children is processed, at every level.
17
18
  * - The primary (winning) element keeps its `key`, `source`, and `type`; the secondary's `title`, `description`,
18
19
  * `content`, and `children` are folded in via `mergeTreeElements()`.
19
20
  * - A secondary with no matching primary is left in place — pure prose files (e.g. `concepts.md` with no `concepts.ts`) stand alone.
@@ -26,14 +27,15 @@ export class MergingExtractor extends ThroughExtractor {
26
27
  }
27
28
  async extract(input) {
28
29
  const root = await this.source.extract(input);
29
- return _mergeDirectory(root, this._merges);
30
+ return _mergeElement(root, this._merges);
30
31
  }
31
32
  }
32
- /** Recursively merge same-template siblings inside `dir` and all nested directories. */
33
- function _mergeDirectory(dir, merges) {
34
- const children = Array.from(walkElements(dir.props.children));
35
- const merged = _mergeChildren(children, merges).map(child => child.type === "tree-directory" ? _mergeDirectory(child, merges) : child);
36
- return { ...dir, props: { ...dir.props, children: merged } };
33
+ /** Recursively merge same-template siblings inside `element` and all of its descendants that have children. */
34
+ function _mergeElement(element, merges) {
35
+ const children = Array.from(walkElements(element.props.children));
36
+ // Recurse into any child that has its own children; childless leaves (e.g. files) are left untouched.
37
+ const merged = _mergeChildren(children, merges).map(child => (notNullish(child.props.children) ? _mergeElement(child, merges) : child));
38
+ return { ...element, props: { ...element.props, children: merged } };
37
39
  }
38
40
  /** Merge same-template siblings at one directory level. */
39
41
  function _mergeChildren(children, merges) {
@@ -1,4 +1,4 @@
1
- import { type DirectoryElement, type DocumentationElement, type FileElement } from "../util/element.js";
1
+ import type { DocumentationElement, TreeElement } from "../util/tree.js";
2
2
  import { Extractor } from "./Extractor.js";
3
3
  /** Input for a `ModuleExtractor`. */
4
4
  export interface ModuleExtractorInput {
@@ -6,15 +6,15 @@ export interface ModuleExtractorInput {
6
6
  readonly name: string;
7
7
  /**
8
8
  * The source element this module is built from.
9
- * - `FileElement` — the module is backed by a single source file (with its `.md` sibling already merged in by `MergingExtractor`).
10
- * - `DirectoryElement` — the module is backed by a directory; its absorbed index file provides the content.
9
+ * - A file-backed `tree-element` — the module is backed by a single source file (with its `.md` sibling already merged in by `MergingExtractor`).
10
+ * - A directory-backed `tree-element` — the module is backed by a directory; its absorbed index file provides the content.
11
11
  */
12
- readonly source: FileElement | DirectoryElement;
12
+ readonly source: TreeElement;
13
13
  }
14
14
  /**
15
15
  * Extractor that builds a `kind: "module"` `DocumentationElement` from a source file or directory.
16
16
  * - The module's `content`, `description`, and `title` are taken from the source element (`MergingExtractor` and
17
- * `IndexFileExtractor` are expected to have run upstream so `.md` siblings and `README.md` are already folded in).
17
+ * `IndexExtractor` are expected to have run upstream so `.md` siblings and `README.md` are already folded in).
18
18
  * - The module's `children` are every `tree-documentation` element found by deep-walking the source — flattened across
19
19
  * files and subdirectories, but never descending into a `tree-documentation`'s own members.
20
20
  */
@@ -4,7 +4,7 @@ import { Extractor } from "./Extractor.js";
4
4
  /**
5
5
  * Extractor that builds a `kind: "module"` `DocumentationElement` from a source file or directory.
6
6
  * - The module's `content`, `description`, and `title` are taken from the source element (`MergingExtractor` and
7
- * `IndexFileExtractor` are expected to have run upstream so `.md` siblings and `README.md` are already folded in).
7
+ * `IndexExtractor` are expected to have run upstream so `.md` siblings and `README.md` are already folded in).
8
8
  * - The module's `children` are every `tree-documentation` element found by deep-walking the source — flattened across
9
9
  * files and subdirectories, but never descending into a `tree-documentation`'s own members.
10
10
  */
@@ -33,7 +33,7 @@ function _collectChildren(element) {
33
33
  if (treeChild.type === "tree-documentation") {
34
34
  result.push(treeChild);
35
35
  }
36
- else if (treeChild.type === "tree-directory" || treeChild.type === "tree-file") {
36
+ else if (treeChild.type === "tree-element") {
37
37
  result.push(..._collectChildren(treeChild));
38
38
  }
39
39
  }
@@ -1,20 +1,22 @@
1
- import { type DirectoryElement } from "../util/element.js";
1
+ import type { ImmutableDictionary } from "../util/dictionary.js";
2
2
  import { type AbsolutePath, type Path } from "../util/path.js";
3
+ import type { TreeElement } from "../util/tree.js";
3
4
  import { Extractor } from "./Extractor.js";
4
5
  import { ModuleExtractor } from "./ModuleExtractor.js";
5
6
  /** Options for a `PackageExtractor`. */
6
7
  export interface PackageExtractorOptions {
7
8
  /**
8
9
  * Pre-extracted source tree the `package.json` exports resolve against — typically the result of
9
- * `IndexFileExtractor(MergingExtractor(DirectoryExtractor()))` over the source root.
10
+ * `IndexExtractor(MergingExtractor(DirectoryExtractor()))` over the source root.
10
11
  */
11
- readonly tree: DirectoryElement;
12
+ readonly tree: TreeElement;
12
13
  /**
13
- * Source-file extensions tried when resolving an export's last segment to a source file (e.g. `./util/string` `string.ts`, `string.tsx`, …).
14
- * - Checked in declaration order; first match wins.
15
- * - Defaults to `["ts", "tsx", "js", "jsx"]`.
14
+ * Maps an export *target* file extension (the right-hand side of an `exports` entry) to the *source* extensions to look for, in order.
15
+ * - Bridges built output and source: `package.json` targets a `.js` file but the tree holds the `.ts` source.
16
+ * - The first source extension that exists in the tree wins; a target extension with no mapping falls back to itself.
17
+ * - Defaults to `{ js: ["ts", "tsx", "js", "jsx"] }`.
16
18
  */
17
- readonly extensions?: readonly string[];
19
+ readonly extensions?: ImmutableDictionary<readonly string[]>;
18
20
  /** `ModuleExtractor` used to build each module element. Defaults to a fresh `new ModuleExtractor()`. */
19
21
  readonly module?: ModuleExtractor;
20
22
  /** Absolute base path used to resolve a relative `package.json` path passed to `extract()`. */
@@ -24,18 +26,20 @@ export interface PackageExtractorOptions {
24
26
  * Extractor that reads a `package.json` and produces a flat tree of modules — one `kind: "module"`
25
27
  * `DocumentationElement` per export entry, in declaration order.
26
28
  * - Static export keys (e.g. `"./api"`, `"./firestore/client"`) become one module each.
27
- * - Wildcard export keys (e.g. `"./util/*"`) expand against the source tree — one module per matching child file (with
28
- * an extension in `extensions`) or subdirectory.
29
+ * - Wildcard export keys (e.g. `"./util/*"`) expand against the source tree — one module per matching child file or subdirectory.
30
+ * - Each export's *target* extension (e.g. the `.js` in `"./util/*.js"`) is mapped to source extensions via `extensions`, so built `.js` paths resolve to their `.ts` sources.
29
31
  * - The `"."` root export is skipped — its content is the root tree element itself.
30
32
  * - Throws if a static export key has no matching source element in the tree.
31
33
  */
32
- export declare class PackageExtractor extends Extractor<Path, DirectoryElement> {
34
+ export declare class PackageExtractor extends Extractor<Path, TreeElement> {
33
35
  private readonly _tree;
34
36
  private readonly _extensions;
35
37
  private readonly _module;
36
38
  private readonly _base;
37
39
  constructor({ tree, extensions, module, base }: PackageExtractorOptions);
38
- extract(packageJson: Path): Promise<DirectoryElement>;
40
+ extract(packageJson: Path): Promise<TreeElement>;
41
+ /** Source extensions to try for an export `target`, derived from the target's own extension via the `extensions` mapping. */
42
+ private _sourceExtensions;
39
43
  /** Resolve a static export subpath (e.g. `"firestore/client"`) to a file or directory element in the tree. */
40
44
  private _resolve;
41
45
  /** Expand a wildcard export subpath (e.g. `"util/*"`) into one module per matching child. */
@@ -2,14 +2,20 @@ import { walkElements } from "../util/element.js";
2
2
  import { requirePath } from "../util/path.js";
3
3
  import { Extractor } from "./Extractor.js";
4
4
  import { ModuleExtractor } from "./ModuleExtractor.js";
5
- /** Default source-file extensions used when resolving exports back to source elements. */
6
- const DEFAULT_EXTENSIONS = ["ts", "tsx", "js", "jsx"];
5
+ /**
6
+ * Default extension mapping: maps an export *target* file extension to the *source* extensions to resolve against, in order.
7
+ * - `package.json` targets point at built output (e.g. `./util/*.js`), but the source tree holds source files (e.g. `string.ts`) — this bridges the two.
8
+ * - A `.js` target finds its `.ts` / `.tsx` / `.js` / `.jsx` source (first match wins).
9
+ */
10
+ const DEFAULT_EXTENSIONS = {
11
+ js: ["ts", "tsx", "js", "jsx"],
12
+ };
7
13
  /**
8
14
  * Extractor that reads a `package.json` and produces a flat tree of modules — one `kind: "module"`
9
15
  * `DocumentationElement` per export entry, in declaration order.
10
16
  * - Static export keys (e.g. `"./api"`, `"./firestore/client"`) become one module each.
11
- * - Wildcard export keys (e.g. `"./util/*"`) expand against the source tree — one module per matching child file (with
12
- * an extension in `extensions`) or subdirectory.
17
+ * - Wildcard export keys (e.g. `"./util/*"`) expand against the source tree — one module per matching child file or subdirectory.
18
+ * - Each export's *target* extension (e.g. the `.js` in `"./util/*.js"`) is mapped to source extensions via `extensions`, so built `.js` paths resolve to their `.ts` sources.
13
19
  * - The `"."` root export is skipped — its content is the root tree element itself.
14
20
  * - Throws if a static export key has no matching source element in the tree.
15
21
  */
@@ -30,23 +36,28 @@ export class PackageExtractor extends Extractor {
30
36
  const pkg = (await Bun.file(pkgPath).json());
31
37
  const exports = pkg.exports ?? {};
32
38
  const modules = [];
33
- for (const key of Object.keys(exports)) {
39
+ for (const [key, value] of Object.entries(exports)) {
34
40
  if (key === ".")
35
41
  continue;
42
+ // `value` is the target (e.g. `"./util/*.js"`); conditional-export objects aren't supported.
43
+ if (typeof value !== "string")
44
+ continue;
36
45
  const subpath = key.startsWith("./") ? key.slice(2) : key;
46
+ const sourceExtensions = this._sourceExtensions(value);
37
47
  if (subpath.includes("*")) {
38
- modules.push(...this._expandWildcard(subpath));
48
+ modules.push(...this._expandWildcard(subpath, sourceExtensions));
39
49
  }
40
50
  else {
41
- const source = this._resolve(subpath);
51
+ const source = this._resolve(subpath, sourceExtensions);
42
52
  if (!source)
43
53
  throw new Error(`PackageExtractor: export "${key}" has no matching source in the tree`);
44
54
  modules.push(this._module.extract({ name: subpath, source }));
45
55
  }
46
56
  }
47
57
  const tree = this._tree;
58
+ // Canonical URL `path`s aren't stamped here — they're derived from tree structure when the tree is flattened (`flattenTree()`) in the UI layer.
48
59
  return {
49
- type: "tree-directory",
60
+ type: "tree-element",
50
61
  key: pkg.name ?? tree.key,
51
62
  props: {
52
63
  source: tree.props.source,
@@ -58,8 +69,14 @@ export class PackageExtractor extends Extractor {
58
69
  },
59
70
  };
60
71
  }
72
+ /** Source extensions to try for an export `target`, derived from the target's own extension via the `extensions` mapping. */
73
+ _sourceExtensions(target) {
74
+ const dot = target.lastIndexOf(".");
75
+ const ext = dot >= 0 ? target.slice(dot + 1) : "";
76
+ return this._extensions[ext] ?? (ext ? [ext] : []);
77
+ }
61
78
  /** Resolve a static export subpath (e.g. `"firestore/client"`) to a file or directory element in the tree. */
62
- _resolve(subpath) {
79
+ _resolve(subpath, sourceExtensions) {
63
80
  const segments = subpath.split("/");
64
81
  let current = this._tree;
65
82
  for (let i = 0; i < segments.length; i++) {
@@ -68,15 +85,15 @@ export class PackageExtractor extends Extractor {
68
85
  let found;
69
86
  for (const child of walkElements(current.props.children)) {
70
87
  const treeChild = child;
71
- if (treeChild.type === "tree-directory" && treeChild.key === segment) {
88
+ // A directory's key is the bare segment name — match at any level.
89
+ if (treeChild.key === segment) {
72
90
  found = treeChild;
73
91
  break;
74
92
  }
75
- if (isLast && treeChild.type === "tree-file") {
76
- if (this._extensions.some(ext => treeChild.key === `${segment}.${ext}`)) {
77
- found = treeChild;
78
- break;
79
- }
93
+ // A file's key is `${segment}.${ext}` for one of the source extensions — only valid as the final segment.
94
+ if (isLast && sourceExtensions.some(ext => treeChild.key === `${segment}.${ext}`)) {
95
+ found = treeChild;
96
+ break;
80
97
  }
81
98
  }
82
99
  if (!found)
@@ -86,7 +103,7 @@ export class PackageExtractor extends Extractor {
86
103
  return current;
87
104
  }
88
105
  /** Expand a wildcard export subpath (e.g. `"util/*"`) into one module per matching child. */
89
- _expandWildcard(subpath) {
106
+ _expandWildcard(subpath, sourceExtensions) {
90
107
  const wildcardIndex = subpath.indexOf("*");
91
108
  const prefix = subpath.slice(0, wildcardIndex);
92
109
  const suffix = subpath.slice(wildcardIndex + 1);
@@ -94,38 +111,30 @@ export class PackageExtractor extends Extractor {
94
111
  throw new Error(`PackageExtractor: wildcard exports with a suffix are not supported ("${subpath}")`);
95
112
  if (subpath.indexOf("*", wildcardIndex + 1) >= 0)
96
113
  throw new Error(`PackageExtractor: multiple wildcards not supported ("${subpath}")`);
97
- // The parent directory of the wildcard.
114
+ // The parent element of the wildcard.
98
115
  const prefixPath = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
99
116
  let parent;
100
117
  if (!prefixPath) {
101
118
  parent = this._tree;
102
119
  }
103
120
  else {
104
- const resolved = this._resolve(prefixPath);
105
- if (!resolved || resolved.type !== "tree-directory") {
106
- throw new Error(`PackageExtractor: wildcard parent "${prefixPath}" did not resolve to a directory`);
107
- }
121
+ const resolved = this._resolve(prefixPath, sourceExtensions);
122
+ if (!resolved)
123
+ throw new Error(`PackageExtractor: wildcard parent "${prefixPath}" did not resolve to an element in the tree`);
108
124
  parent = resolved;
109
125
  }
110
- // One module per qualifying child of the parent directory.
126
+ // One module per qualifying child. A child's `name` is already its extension-stripped module name (e.g. `string.ts` → `string`, the `util` directory → `util`).
111
127
  const modules = [];
112
128
  for (const child of walkElements(parent.props.children)) {
113
129
  const treeChild = child;
114
- let stem;
115
- if (treeChild.type === "tree-directory") {
116
- stem = treeChild.key;
117
- }
118
- else if (treeChild.type === "tree-file") {
119
- for (const ext of this._extensions) {
120
- if (treeChild.key.endsWith(`.${ext}`)) {
121
- stem = treeChild.key.slice(0, -(ext.length + 1));
122
- break;
123
- }
124
- }
125
- }
126
- if (!stem)
130
+ if (treeChild.type !== "tree-element")
131
+ continue;
132
+ // Include directories (no extension) and source files (extension in the mapped list); skip other files (e.g. a standalone `.md`).
133
+ const dot = treeChild.key.lastIndexOf(".");
134
+ const ext = dot >= 0 ? treeChild.key.slice(dot + 1) : "";
135
+ if (ext && !sourceExtensions.includes(ext))
127
136
  continue;
128
- modules.push(this._module.extract({ name: `${prefix}${stem}`, source: treeChild }));
137
+ modules.push(this._module.extract({ name: `${prefix}${treeChild.props.name}`, source: treeChild }));
129
138
  }
130
139
  return modules;
131
140
  }
@@ -1,4 +1,4 @@
1
- import type { TreeElement } from "../util/element.js";
1
+ import type { TreeElement } from "../util/tree.js";
2
2
  import { Extractor } from "./Extractor.js";
3
3
  /**
4
4
  * Base class for an extractor that wraps another extractor.
@@ -1,17 +1,21 @@
1
- import type { FileElementProps } from "../util/element.js";
1
+ import type { TreeElementProps } from "../util/tree.js";
2
2
  import { FileExtractor } from "./FileExtractor.js";
3
3
  /**
4
4
  * File extractor that parses a TypeScript source file into a tree element.
5
5
  * - Uses the TypeScript compiler API to parse the AST.
6
6
  * - Extracts exported, public, non-`_`-prefixed declarations as `tree-documentation` children.
7
7
  * - Overloaded declarations sharing a name are merged into a single `tree-documentation` with multiple `signatures`.
8
+ * - Class declarations synthesise their `signatures`, `params`, and `returns` from the constructor — `new ClassName<…>(…)` including generics, one signature per constructor overload, with `returns` set to the class type. Param descriptions come from the constructor's `@param` first, then the class's `@param`.
8
9
  * - Top-of-file JSDoc comment becomes the file's `content`.
9
10
  * - Sets `description` (a plain-text summary from the first JSDoc paragraph) on the file and every `tree-documentation` child.
10
- * - Sets `title` on every `tree-documentation` child — `name()` for functions and methods, `name` for other kinds.
11
+ * - Sets `title` on every `tree-documentation` child — `name()` for functions and methods, bare `name` for other kinds. Parent class context comes from the `class` prop ("member of …" affordance), never the title.
12
+ * - Records relational metadata as raw strings for render-time linking: `class` (owning class), `readonly`, `extends`, `implements`.
13
+ * - Members declared with the `override` or `declare` modifier are skipped — the base class already documents overrides, and `declare` members are ambient type-only re-declarations rather than new API.
14
+ * - Keys are the raw declared `name` (case-preserving) so case-distinct exports like `Collection` and `COLLECTION` stay separate.
11
15
  * - The file element itself has no `title` — a TS source file has no confident title source; renderers fall back to `name`.
12
16
  */
13
17
  export declare class TypescriptExtractor extends FileExtractor {
14
- extractProps(name: string, text: string): Partial<FileElementProps> & {
18
+ extractProps(name: string, text: string): Partial<TreeElementProps> & {
15
19
  name: string;
16
20
  };
17
21
  }