@hubspot/ui-extensions-sdk-api-metadata 0.12.0 → 0.12.2

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.
@@ -1,14 +1,295 @@
1
1
  import path from 'node:path';
2
2
  import { ComponentName, getComponentPropsDocumentation } from "../index.js";
3
3
  const snapshotsDir = path.join(__dirname, '__snapshots__');
4
- const runComponentPropsSnapshotTest = (componentName) => {
4
+ const runComponentPropsSnapshotTest = async (componentName) => {
5
5
  const propsDocumentation = getComponentPropsDocumentation(componentName);
6
- expect(`${JSON.stringify(propsDocumentation, null, 2)}\n`).toMatchFileSnapshot(path.join(snapshotsDir, `${componentName}.snapshot.json`));
6
+ await expect(`${JSON.stringify(propsDocumentation, null, 2)}\n`).toMatchFileSnapshot(path.join(snapshotsDir, `${componentName}.snapshot.json`));
7
7
  };
8
8
  describe('getComponentPropsDocumentation', () => {
9
- it('should return the correct component prop documentation for the Accordion component', () => {
10
- runComponentPropsSnapshotTest(ComponentName.Accordion);
9
+ it('should return the correct component prop documentation for the Accordion component', async () => {
10
+ await runComponentPropsSnapshotTest(ComponentName.Accordion);
11
+ });
12
+ it('should return the correct component prop documentation for the Alert component', async () => {
13
+ await runComponentPropsSnapshotTest(ComponentName.Alert);
14
+ });
15
+ it('should return the correct component prop documentation for the AutoGrid component', async () => {
16
+ await runComponentPropsSnapshotTest(ComponentName.AutoGrid);
17
+ });
18
+ it('should return the correct component prop documentation for the BarChart component', async () => {
19
+ await runComponentPropsSnapshotTest(ComponentName.BarChart);
20
+ });
21
+ it('should return the correct component prop documentation for the Box component', async () => {
22
+ await runComponentPropsSnapshotTest(ComponentName.Box);
23
+ });
24
+ it('should return the correct component prop documentation for the Button component', async () => {
25
+ await runComponentPropsSnapshotTest(ComponentName.Button);
26
+ });
27
+ it('should return the correct component prop documentation for the ButtonRow component', async () => {
28
+ await runComponentPropsSnapshotTest(ComponentName.ButtonRow);
29
+ });
30
+ it('should return the correct component prop documentation for the Card component', async () => {
31
+ await runComponentPropsSnapshotTest(ComponentName.Card);
32
+ });
33
+ it('should return the correct component prop documentation for the Center component', async () => {
34
+ await runComponentPropsSnapshotTest(ComponentName.Center);
35
+ });
36
+ it('should return the correct component prop documentation for the Checkbox component', async () => {
37
+ await runComponentPropsSnapshotTest(ComponentName.Checkbox);
38
+ });
39
+ it('should return the correct component prop documentation for the CrmActionButton component', async () => {
40
+ await runComponentPropsSnapshotTest(ComponentName.CrmActionButton);
41
+ });
42
+ it('should return the correct component prop documentation for the CrmActionLink component', async () => {
43
+ await runComponentPropsSnapshotTest(ComponentName.CrmActionLink);
44
+ });
45
+ it('should return the correct component prop documentation for the CrmAssociationPivot component', async () => {
46
+ await runComponentPropsSnapshotTest(ComponentName.CrmAssociationPivot);
47
+ });
48
+ it('should return the correct component prop documentation for the CrmAssociationPropertyList component', async () => {
49
+ await runComponentPropsSnapshotTest(ComponentName.CrmAssociationPropertyList);
50
+ });
51
+ it('should return the correct component prop documentation for the CrmAssociationStageTracker component', async () => {
52
+ await runComponentPropsSnapshotTest(ComponentName.CrmAssociationStageTracker);
53
+ });
54
+ it('should return the correct component prop documentation for the CrmAssociationTable component', async () => {
55
+ await runComponentPropsSnapshotTest(ComponentName.CrmAssociationTable);
56
+ });
57
+ it('should return the correct component prop documentation for the CrmCardActions component', async () => {
58
+ await runComponentPropsSnapshotTest(ComponentName.CrmCardActions);
59
+ });
60
+ it('should return the correct component prop documentation for the CrmDataHighlight component', async () => {
61
+ await runComponentPropsSnapshotTest(ComponentName.CrmDataHighlight);
62
+ });
63
+ it('should return the correct component prop documentation for the CrmPropertyList component', async () => {
64
+ await runComponentPropsSnapshotTest(ComponentName.CrmPropertyList);
65
+ });
66
+ it('should return the correct component prop documentation for the CrmReport component', async () => {
67
+ await runComponentPropsSnapshotTest(ComponentName.CrmReport);
68
+ });
69
+ it('should return the correct component prop documentation for the CrmSimpleDeadline component', async () => {
70
+ await runComponentPropsSnapshotTest(ComponentName.CrmSimpleDeadline);
71
+ });
72
+ it('should return the correct component prop documentation for the CrmStageTracker component', async () => {
73
+ await runComponentPropsSnapshotTest(ComponentName.CrmStageTracker);
74
+ });
75
+ it('should return the correct component prop documentation for the CrmStatistics component', async () => {
76
+ await runComponentPropsSnapshotTest(ComponentName.CrmStatistics);
77
+ });
78
+ it('should return the correct component prop documentation for the CurrencyInput component', async () => {
79
+ await runComponentPropsSnapshotTest(ComponentName.CurrencyInput);
80
+ });
81
+ it('should return the correct component prop documentation for the DateInput component', async () => {
82
+ await runComponentPropsSnapshotTest(ComponentName.DateInput);
83
+ });
84
+ it('should return the correct component prop documentation for the DescriptionList component', async () => {
85
+ await runComponentPropsSnapshotTest(ComponentName.DescriptionList);
86
+ });
87
+ it('should return the correct component prop documentation for the DescriptionListItem component', async () => {
88
+ await runComponentPropsSnapshotTest(ComponentName.DescriptionListItem);
89
+ });
90
+ it('should return the correct component prop documentation for the Divider component', async () => {
91
+ await runComponentPropsSnapshotTest(ComponentName.Divider);
92
+ });
93
+ it('should return the correct component prop documentation for the Dropdown component', async () => {
94
+ await runComponentPropsSnapshotTest(ComponentName.Dropdown);
95
+ });
96
+ it('should return the correct component prop documentation for the DropdownButtonItem component', async () => {
97
+ await runComponentPropsSnapshotTest(ComponentName.DropdownButtonItem);
98
+ });
99
+ it('should return the correct component prop documentation for the EmptyState component', async () => {
100
+ await runComponentPropsSnapshotTest(ComponentName.EmptyState);
101
+ });
102
+ it('should return the correct component prop documentation for the ErrorState component', async () => {
103
+ await runComponentPropsSnapshotTest(ComponentName.ErrorState);
104
+ });
105
+ it('should return the correct component prop documentation for the ExpandableText component', async () => {
106
+ await runComponentPropsSnapshotTest(ComponentName.ExpandableText);
107
+ });
108
+ it('should return the correct component prop documentation for the FileInput component', async () => {
109
+ await runComponentPropsSnapshotTest(ComponentName.FileInput);
110
+ });
111
+ it('should return the correct component prop documentation for the Flex component', async () => {
112
+ await runComponentPropsSnapshotTest(ComponentName.Flex);
113
+ });
114
+ it('should return the correct component prop documentation for the Form component', async () => {
115
+ await runComponentPropsSnapshotTest(ComponentName.Form);
116
+ });
117
+ it('should return the correct component prop documentation for the Grid component', async () => {
118
+ await runComponentPropsSnapshotTest(ComponentName.Grid);
119
+ });
120
+ it('should return the correct component prop documentation for the GridItem component', async () => {
121
+ await runComponentPropsSnapshotTest(ComponentName.GridItem);
122
+ });
123
+ it('should return the correct component prop documentation for the HeaderActions component', async () => {
124
+ await runComponentPropsSnapshotTest(ComponentName.HeaderActions);
125
+ });
126
+ it('should return the correct component prop documentation for the Heading component', async () => {
127
+ await runComponentPropsSnapshotTest(ComponentName.Heading);
128
+ });
129
+ it('should return the correct component prop documentation for the Icon component', async () => {
130
+ await runComponentPropsSnapshotTest(ComponentName.Icon);
131
+ });
132
+ it('should return the correct component prop documentation for the Iframe component', async () => {
133
+ await runComponentPropsSnapshotTest(ComponentName.Iframe);
134
+ });
135
+ it('should return the correct component prop documentation for the Illustration component', async () => {
136
+ await runComponentPropsSnapshotTest(ComponentName.Illustration);
137
+ });
138
+ it('should return the correct component prop documentation for the Image component', async () => {
139
+ await runComponentPropsSnapshotTest(ComponentName.Image);
140
+ });
141
+ it('should return the correct component prop documentation for the Inline component', async () => {
142
+ await runComponentPropsSnapshotTest(ComponentName.Inline);
143
+ });
144
+ it('should return the correct component prop documentation for the Input component', async () => {
145
+ await runComponentPropsSnapshotTest(ComponentName.Input);
146
+ });
147
+ it('should return the correct component prop documentation for the LineChart component', async () => {
148
+ await runComponentPropsSnapshotTest(ComponentName.LineChart);
149
+ });
150
+ it('should return the correct component prop documentation for the Link component', async () => {
151
+ await runComponentPropsSnapshotTest(ComponentName.Link);
152
+ });
153
+ it('should return the correct component prop documentation for the List component', async () => {
154
+ await runComponentPropsSnapshotTest(ComponentName.List);
155
+ });
156
+ it('should return the correct component prop documentation for the LoadingButton component', async () => {
157
+ await runComponentPropsSnapshotTest(ComponentName.LoadingButton);
158
+ });
159
+ it('should return the correct component prop documentation for the LoadingSpinner component', async () => {
160
+ await runComponentPropsSnapshotTest(ComponentName.LoadingSpinner);
161
+ });
162
+ it('should return the correct component prop documentation for the MediaObject component', async () => {
163
+ await runComponentPropsSnapshotTest(ComponentName.MediaObject);
164
+ });
165
+ it('should return the correct component prop documentation for the Modal component', async () => {
166
+ await runComponentPropsSnapshotTest(ComponentName.Modal);
167
+ });
168
+ it('should return the correct component prop documentation for the ModalBody component', async () => {
169
+ await runComponentPropsSnapshotTest(ComponentName.ModalBody);
170
+ });
171
+ it('should return the correct component prop documentation for the ModalFooter component', async () => {
172
+ await runComponentPropsSnapshotTest(ComponentName.ModalFooter);
173
+ });
174
+ it('should return the correct component prop documentation for the MultiSelect component', async () => {
175
+ await runComponentPropsSnapshotTest(ComponentName.MultiSelect);
176
+ });
177
+ it('should return the correct component prop documentation for the NumberInput component', async () => {
178
+ await runComponentPropsSnapshotTest(ComponentName.NumberInput);
179
+ });
180
+ it('should return the correct component prop documentation for the Panel component', async () => {
181
+ await runComponentPropsSnapshotTest(ComponentName.Panel);
182
+ });
183
+ it('should return the correct component prop documentation for the PanelBody component', async () => {
184
+ await runComponentPropsSnapshotTest(ComponentName.PanelBody);
185
+ });
186
+ it('should return the correct component prop documentation for the PanelFooter component', async () => {
187
+ await runComponentPropsSnapshotTest(ComponentName.PanelFooter);
188
+ });
189
+ it('should return the correct component prop documentation for the PanelSection component', async () => {
190
+ await runComponentPropsSnapshotTest(ComponentName.PanelSection);
191
+ });
192
+ it('should return the correct component prop documentation for the Popover component', async () => {
193
+ await runComponentPropsSnapshotTest(ComponentName.Popover);
194
+ });
195
+ it('should return the correct component prop documentation for the PrimaryHeaderActionButton component', async () => {
196
+ await runComponentPropsSnapshotTest(ComponentName.PrimaryHeaderActionButton);
197
+ });
198
+ it('should return the correct component prop documentation for the ProgressBar component', async () => {
199
+ await runComponentPropsSnapshotTest(ComponentName.ProgressBar);
200
+ });
201
+ // FIXME: RadioButtonProps is not currently supported because it is a union type and not an object type.
202
+ it.skip('should return the correct component prop documentation for the RadioButton component', async () => {
203
+ await runComponentPropsSnapshotTest(ComponentName.RadioButton);
204
+ });
205
+ it('should return the correct component prop documentation for the ScoreCircle component', async () => {
206
+ await runComponentPropsSnapshotTest(ComponentName.ScoreCircle);
207
+ });
208
+ it('should return the correct component prop documentation for the SearchInput component', async () => {
209
+ await runComponentPropsSnapshotTest(ComponentName.SearchInput);
210
+ });
211
+ it('should return the correct component prop documentation for the SecondaryHeaderActionButton component', async () => {
212
+ await runComponentPropsSnapshotTest(ComponentName.SecondaryHeaderActionButton);
213
+ });
214
+ it('should return the correct component prop documentation for the Select component', async () => {
215
+ await runComponentPropsSnapshotTest(ComponentName.Select);
216
+ });
217
+ it('should return the correct component prop documentation for the SettingsView component', async () => {
218
+ await runComponentPropsSnapshotTest(ComponentName.SettingsView);
219
+ });
220
+ it('should return the correct component prop documentation for the Stack2 component', async () => {
221
+ await runComponentPropsSnapshotTest(ComponentName.Stack2);
222
+ });
223
+ it('should return the correct component prop documentation for the Statistics component', async () => {
224
+ await runComponentPropsSnapshotTest(ComponentName.Statistics);
225
+ });
226
+ it('should return the correct component prop documentation for the StatisticsItem component', async () => {
227
+ await runComponentPropsSnapshotTest(ComponentName.StatisticsItem);
228
+ });
229
+ it('should return the correct component prop documentation for the StatisticsTrend component', async () => {
230
+ await runComponentPropsSnapshotTest(ComponentName.StatisticsTrend);
231
+ });
232
+ it('should return the correct component prop documentation for the StatusTag component', async () => {
233
+ await runComponentPropsSnapshotTest(ComponentName.StatusTag);
234
+ });
235
+ it('should return the correct component prop documentation for the StepIndicator component', async () => {
236
+ await runComponentPropsSnapshotTest(ComponentName.StepIndicator);
237
+ });
238
+ it('should return the correct component prop documentation for the StepperInput component', async () => {
239
+ await runComponentPropsSnapshotTest(ComponentName.StepperInput);
240
+ });
241
+ it('should return the correct component prop documentation for the Tab component', async () => {
242
+ await runComponentPropsSnapshotTest(ComponentName.Tab);
243
+ });
244
+ // FIXME: TableProps is not currently supported because it is a union type and not an object type.
245
+ it.skip('should return the correct component prop documentation for the Table component', async () => {
246
+ await runComponentPropsSnapshotTest(ComponentName.Table);
247
+ });
248
+ it('should return the correct component prop documentation for the TableBody component', async () => {
249
+ await runComponentPropsSnapshotTest(ComponentName.TableBody);
250
+ });
251
+ it('should return the correct component prop documentation for the TableCell component', async () => {
252
+ await runComponentPropsSnapshotTest(ComponentName.TableCell);
253
+ });
254
+ it('should return the correct component prop documentation for the TableFooter component', async () => {
255
+ await runComponentPropsSnapshotTest(ComponentName.TableFooter);
256
+ });
257
+ it('should return the correct component prop documentation for the TableHead component', async () => {
258
+ await runComponentPropsSnapshotTest(ComponentName.TableHead);
259
+ });
260
+ // FIXME: TableHeaderProps is not currently supported because it is a union type and not an object type.
261
+ it.skip('should return the correct component prop documentation for the TableHeader component', async () => {
262
+ await runComponentPropsSnapshotTest(ComponentName.TableHeader);
263
+ });
264
+ it('should return the correct component prop documentation for the TableRow component', async () => {
265
+ await runComponentPropsSnapshotTest(ComponentName.TableRow);
266
+ });
267
+ it('should return the correct component prop documentation for the Tabs component', async () => {
268
+ await runComponentPropsSnapshotTest(ComponentName.Tabs);
269
+ });
270
+ it('should return the correct component prop documentation for the Tag component', async () => {
271
+ await runComponentPropsSnapshotTest(ComponentName.Tag);
272
+ });
273
+ it('should return the correct component prop documentation for the Text component', async () => {
274
+ await runComponentPropsSnapshotTest(ComponentName.Text);
275
+ });
276
+ it('should return the correct component prop documentation for the TextArea component', async () => {
277
+ await runComponentPropsSnapshotTest(ComponentName.TextArea);
278
+ });
279
+ it('should return the correct component prop documentation for the Tile component', async () => {
280
+ await runComponentPropsSnapshotTest(ComponentName.Tile);
281
+ });
282
+ it('should return the correct component prop documentation for the TimeInput component', async () => {
283
+ await runComponentPropsSnapshotTest(ComponentName.TimeInput);
284
+ });
285
+ it('should return the correct component prop documentation for the Toggle component', async () => {
286
+ await runComponentPropsSnapshotTest(ComponentName.Toggle);
287
+ });
288
+ // FIXME: ToggleGroupProps is not currently supported because it is a union type and not an object type.
289
+ it.skip('should return the correct component prop documentation for the ToggleGroup component', async () => {
290
+ await runComponentPropsSnapshotTest(ComponentName.ToggleGroup);
291
+ });
292
+ it('should return the correct component prop documentation for the Tooltip component', async () => {
293
+ await runComponentPropsSnapshotTest(ComponentName.Tooltip);
11
294
  });
12
- // NOTE: We will continue to add more snapshot tests for each component so that we can verify that
13
- // we are producing the correct documentation for each component.
14
295
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,162 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { convertHtmlToJsx, wrapCodeInHtmlCodeTags, } from "../internal/utils/jsx-utils.js";
3
+ describe('convertHtmlToJsx', () => {
4
+ describe('void elements', () => {
5
+ it('should convert <br> to self-closing tag', () => {
6
+ const input = '<strong>Hello<br>World</strong>';
7
+ const output = convertHtmlToJsx(input);
8
+ expect(output).toBe('<><strong>Hello<br />World</strong></>');
9
+ });
10
+ it('should convert <hr> to self-closing tag', () => {
11
+ const input = '<div>Section 1<hr>Section 2</div>';
12
+ const output = convertHtmlToJsx(input);
13
+ expect(output).toBe('<><div>Section 1<hr />Section 2</div></>');
14
+ });
15
+ it('should convert <img> to self-closing tag', () => {
16
+ const input = '<img src="test.png">';
17
+ const output = convertHtmlToJsx(input);
18
+ expect(output).toBe('<><img src="test.png" /></>');
19
+ });
20
+ it('should convert <input> to self-closing tag', () => {
21
+ const input = '<input type="text" name="field">';
22
+ const output = convertHtmlToJsx(input);
23
+ expect(output).toBe('<><input type="text" name="field" /></>');
24
+ });
25
+ it('should handle multiple void elements', () => {
26
+ const input = '<div><img src="a.png"><br><img src="b.png"></div>';
27
+ const output = convertHtmlToJsx(input);
28
+ expect(output).toBe('<><div><img src="a.png" /><br /><img src="b.png" /></div></>');
29
+ });
30
+ it('should preserve already self-closing tags', () => {
31
+ const input = '<strong>Hello<br/>World</strong>';
32
+ const output = convertHtmlToJsx(input);
33
+ expect(output).toBe('<><strong>Hello<br />World</strong></>');
34
+ });
35
+ });
36
+ describe('attributes', () => {
37
+ it('should preserve attributes on void elements', () => {
38
+ const input = '<img src="test.png" alt="Test Image" width="100">';
39
+ const output = convertHtmlToJsx(input);
40
+ expect(output).toBe('<><img src="test.png" alt="Test Image" width="100" /></>');
41
+ });
42
+ it('should preserve attributes on regular elements', () => {
43
+ const input = '<div class="container" id="main">Content</div>';
44
+ const output = convertHtmlToJsx(input);
45
+ expect(output).toBe('<><div class="container" id="main">Content</div></>');
46
+ });
47
+ it('should handle attributes with special characters', () => {
48
+ const input = '<a href="https://example.com?foo=bar&baz=qux">Link</a>';
49
+ const output = convertHtmlToJsx(input);
50
+ expect(output).toContain('<><a href="https://example.com?foo=bar&amp;baz=qux">Link</a></>');
51
+ });
52
+ });
53
+ describe('nested elements', () => {
54
+ it('should handle nested elements correctly', () => {
55
+ const input = '<div><p>Text with <strong>bold</strong> and <em>italic</em></p></div>';
56
+ const output = convertHtmlToJsx(input);
57
+ expect(output).toBe('<><div><p>Text with <strong>bold</strong> and <em>italic</em></p></div></>');
58
+ });
59
+ it('should handle void elements within nested structures', () => {
60
+ const input = '<div><p>Line 1<br>Line 2</p><hr><p>Line 3</p></div>';
61
+ const output = convertHtmlToJsx(input);
62
+ expect(output).toBe('<><div><p>Line 1<br />Line 2</p><hr /><p>Line 3</p></div></>');
63
+ });
64
+ });
65
+ describe('text content', () => {
66
+ it('should preserve text content', () => {
67
+ const input = '<strong>Hello World</strong>';
68
+ const output = convertHtmlToJsx(input);
69
+ expect(output).toBe('<><strong>Hello World</strong></>');
70
+ });
71
+ it('should preserve whitespace in text', () => {
72
+ const input = 'Hello World';
73
+ const output = convertHtmlToJsx(input);
74
+ expect(output).toBe('<>Hello World</>');
75
+ });
76
+ it('should handle special characters in text', () => {
77
+ const input = '5 &lt; 10 &amp; 10 &gt; 5';
78
+ const output = convertHtmlToJsx(input);
79
+ expect(output).toBe('<>5 &lt; 10 &amp; 10 &gt; 5</>');
80
+ });
81
+ });
82
+ describe('inline elements', () => {
83
+ it('should handle <code> tags', () => {
84
+ const input = 'Use <code>const</code> instead';
85
+ const output = convertHtmlToJsx(input);
86
+ expect(output).toBe('<>Use <code>const</code> instead</>');
87
+ });
88
+ it('should handle <a> tags', () => {
89
+ const input = 'Visit <a href="https://example.com">example</a>';
90
+ const output = convertHtmlToJsx(input);
91
+ expect(output).toEqual('<>Visit <a href="https://example.com">example</a></>');
92
+ });
93
+ it('should handle <strong> and <em> tags', () => {
94
+ const input = '<strong>Bold</strong> and <em>italic</em>';
95
+ const output = convertHtmlToJsx(input);
96
+ expect(output).toBe('<><strong>Bold</strong> and <em>italic</em></>');
97
+ });
98
+ });
99
+ describe('edge cases', () => {
100
+ it('should handle empty elements', () => {
101
+ const input = '<strong></strong>';
102
+ const output = convertHtmlToJsx(input);
103
+ // Empty non-void elements remain as open/close tags (not self-closing)
104
+ expect(output).toBe('<><strong></strong></>');
105
+ });
106
+ it('should handle plain text without tags', () => {
107
+ const input = 'Just plain text';
108
+ const output = convertHtmlToJsx(input);
109
+ expect(output).toBe('<>Just plain text</>');
110
+ });
111
+ it('should handle empty string', () => {
112
+ const input = '';
113
+ const output = convertHtmlToJsx(input);
114
+ expect(output).toBe('<></>');
115
+ });
116
+ it('should handle fragments with multiple root elements', () => {
117
+ const input = '<p>First</p><p>Second</p>';
118
+ const output = convertHtmlToJsx(input);
119
+ expect(output).toBe('<><p>First</p><p>Second</p></>');
120
+ });
121
+ it('should handle list elements', () => {
122
+ const input = '<ul><li>Item 1</li><li>Item 2</li></ul>';
123
+ const output = convertHtmlToJsx(input);
124
+ expect(output).toBe('<><ul><li>Item 1</li><li>Item 2</li></ul></>');
125
+ });
126
+ });
127
+ describe('markdown-like output', () => {
128
+ it('should handle markdown-generated links', () => {
129
+ const input = 'Check out <a href="https://example.com">this link</a> for more';
130
+ const output = convertHtmlToJsx(input);
131
+ expect(output).toEqual('<>Check out <a href="https://example.com">this link</a> for more</>');
132
+ });
133
+ it('should handle markdown-generated code blocks', () => {
134
+ const input = '<p>Use <code>true</code> instead of <code>false</code></p>';
135
+ const output = convertHtmlToJsx(input);
136
+ expect(output).toBe('<>Use <code>true</code> instead of <code>false</code></>');
137
+ });
138
+ it('should handle markdown-generated emphasis', () => {
139
+ const input = '<p>This is <strong>important</strong> and <em>emphasized</em></p>';
140
+ const output = convertHtmlToJsx(input);
141
+ expect(output).toBe('<>This is <strong>important</strong> and <em>emphasized</em></>');
142
+ });
143
+ });
144
+ });
145
+ describe('wrapCodeInHtmlCodeTags', () => {
146
+ it('should wrap text in code tags', () => {
147
+ const result = wrapCodeInHtmlCodeTags('const x = 5');
148
+ expect(result).toBe('<code>const x = 5</code>');
149
+ });
150
+ it('should escape HTML special characters', () => {
151
+ const result = wrapCodeInHtmlCodeTags('<div>');
152
+ expect(result).toBe('<code>&lt;div&gt;</code>');
153
+ });
154
+ it('should escape curly braces for JSX', () => {
155
+ const result = wrapCodeInHtmlCodeTags('{ foo: "bar" }');
156
+ expect(result).toBe('<code>&#123; foo: "bar" &#125;</code>');
157
+ });
158
+ it('should escape ampersands', () => {
159
+ const result = wrapCodeInHtmlCodeTags('a && b');
160
+ expect(result).toBe('<code>a &amp;&amp; b</code>');
161
+ });
162
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import path from 'node:path';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { renderMarkdownToJsx } from "../internal/utils/markdown-utils.js";
4
+ const snapshotsDir = path.join(__dirname, '__snapshots__');
5
+ describe('renderMarkdownToJsx', () => {
6
+ it('should handle a mix of markdown such as lists, code blocks, and links', async () => {
7
+ const input = `[example link](https://example.com) Distributes *components* based on the **available** empty space around them. Options are as follows:
8
+ - \`initial\`: The item is sized according to its width and height properties. It shrinks to its minimum size to fit the container, but does not grow to absorb any extra free space in the flex container.
9
+ - Number: tells a component to fill all available space, shared evenly amongst other components with the same parent. The larger the flex given, the higher the ratio of space a component will take compared to its siblings.`;
10
+ const result = renderMarkdownToJsx(input);
11
+ await expect(result).toMatchFileSnapshot(path.join(snapshotsDir, 'markdown-utils/flex-description.snapshot.html'));
12
+ });
13
+ });
@@ -1,8 +1,8 @@
1
- import { isInlinedTypeReferenceNode, isObjectNode, isTypeReferenceNode, } from '@hubspot/ts-export-types-reader';
1
+ import { isObjectNode, isTypeReferenceNode, } from '@hubspot/ts-export-types-reader';
2
2
  import { componentPropsReader } from "./__generated__/component-props.js";
3
- import { renderPropTypeToHtml, } from "./internal/render-prop-type.js";
4
- import { getDefaultValueFromJsdocTags, getSeeTagsFromJsdocTags, } from "./internal/utils/jsdoc-utils.js";
5
- import { renderInlineMarkdownToHtml } from "./internal/utils/markdown-utils.js";
3
+ import { renderPropTypeToJsx, } from "./internal/render-prop-type.js";
4
+ import { getDefaultValueFromJsdocTags, getSeeTagsFromJsdocTags, hasDeprecatedJsdocTag, } from "./internal/utils/jsdoc-utils.js";
5
+ import { renderMarkdownToJsx } from "./internal/utils/markdown-utils.js";
6
6
  import { getComponentTypeSource } from "./internal/get-type-source.js";
7
7
  /**
8
8
  * Recursively resolves an API node to an ObjectNode if possible.
@@ -27,10 +27,6 @@ const maybeGetPropsObjectHelper = (apiNode) => {
27
27
  if (isObjectNode(apiNode)) {
28
28
  return apiNode;
29
29
  }
30
- // If it's an inlined type reference, recursively resolve the inner type
31
- if (isInlinedTypeReferenceNode(apiNode)) {
32
- return maybeGetPropsObjectHelper(apiNode.type);
33
- }
34
30
  // If it's a type reference, look up the referenced type and resolve it
35
31
  if (isTypeReferenceNode(apiNode)) {
36
32
  const referencedNode = componentPropsReader.findReferencedTypeById(apiNode.typeId);
@@ -45,14 +41,14 @@ const embeddedLinkTagRegex = /\{@link\s+(\S+)(?:\s+([^}]+))?\s*\}/g;
45
41
  * Renders a JSDoc @see tag's text content to HTML.
46
42
  *
47
43
  * Converts embedded `{@link}` tags in the see text to markdown link syntax,
48
- * then renders the markdown to HTML.
44
+ * then renders the markdown to JSX.
49
45
  *
50
46
  * @param seeText - The text of the see tag
51
47
  * @returns The see tag text rendered as HTML
52
48
  */
53
- const renderSeeItemToHtml = (seeText) => {
49
+ const renderSeeItemToJsx = (seeText) => {
54
50
  // Replace all embedded {@link} tags with equivalent markdown link syntax
55
- return renderInlineMarkdownToHtml(seeText.replaceAll(embeddedLinkTagRegex, (match, url, title) => {
51
+ return renderMarkdownToJsx(seeText.replaceAll(embeddedLinkTagRegex, (match, url, title) => {
56
52
  return `[${title ?? url}](${url})`;
57
53
  }));
58
54
  };
@@ -77,8 +73,10 @@ export const getComponentPropsDocumentation = (componentName) => {
77
73
  if (!propsObject) {
78
74
  throw new Error(`Props object not found for component "${componentName}" (${exportName} in ${exportPath})`);
79
75
  }
80
- // Sort properties first by required status, then alphabetically by name for consistent output
81
- const props = [...propsObject.properties].sort((a, b) => {
76
+ // Filter out deprecated properties, then sort by required status and alphabetically by name for consistent output
77
+ const props = [...propsObject.properties]
78
+ .filter((prop) => !hasDeprecatedJsdocTag(prop.jsdoc?.tags))
79
+ .sort((a, b) => {
82
80
  const aRequired = a.isOptional !== true;
83
81
  const bRequired = b.isOptional !== true;
84
82
  if (aRequired !== bRequired) {
@@ -91,24 +89,24 @@ export const getComponentPropsDocumentation = (componentName) => {
91
89
  const jsdocTags = prop.jsdoc?.tags ?? [];
92
90
  const renderTypeContext = {
93
91
  typesReader: componentPropsReader,
94
- foundTypeIds: new Set(),
92
+ typePath: [],
95
93
  };
96
- const typeHtml = renderPropTypeToHtml(renderTypeContext, prop.type);
97
- const descriptionHtml = renderInlineMarkdownToHtml(jsdocText);
94
+ const typeJsx = renderPropTypeToJsx(renderTypeContext, prop.type);
95
+ const descriptionJsx = renderMarkdownToJsx(jsdocText);
98
96
  // Extract default value from JSDoc tags if present
99
97
  const defaultValue = getDefaultValueFromJsdocTags(jsdocTags);
100
- const seeHtmlItems = getSeeTagsFromJsdocTags(jsdocTags).map(renderSeeItemToHtml);
98
+ const seeJsxItems = getSeeTagsFromJsdocTags(jsdocTags).map(renderSeeItemToJsx);
101
99
  const componentProp = {
102
100
  name: prop.name,
103
101
  required: prop.isOptional !== true,
104
- typeJsx: `<>${typeHtml}</>`,
105
- descriptionJsx: `<>${descriptionHtml}</>`,
102
+ typeJsx,
103
+ descriptionJsx,
106
104
  };
107
- if (seeHtmlItems.length > 0) {
108
- componentProp.seeJsxItems = seeHtmlItems.map((seeHtmlItem) => `<>${seeHtmlItem}</>`);
105
+ if (seeJsxItems.length > 0) {
106
+ componentProp.seeJsxItems = seeJsxItems;
109
107
  }
110
108
  if (defaultValue != null) {
111
- componentProp.defaultValueJsx = `<>${renderInlineMarkdownToHtml(defaultValue)}</>`;
109
+ componentProp.defaultValueJsx = renderMarkdownToJsx(defaultValue);
112
110
  }
113
111
  return componentProp;
114
112
  });