@link-assistant/web-capture 1.1.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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.github/workflows/release.yml +294 -0
- package/.jscpd.json +20 -0
- package/.lenv +8 -0
- package/.prettierignore +7 -0
- package/.prettierrc +10 -0
- package/ARCHITECTURE.md +982 -0
- package/CHANGELOG.md +22 -0
- package/Dockerfile +45 -0
- package/LICENSE +24 -0
- package/README.md +268 -0
- package/apply.sh +166 -0
- package/babel.config.cjs +13 -0
- package/bin/web-capture.js +285 -0
- package/docker-compose.yml +9 -0
- package/docs/market-analysis-2025-05-13.md +64 -0
- package/eslint.config.js +112 -0
- package/examples/js/engine_comparison.js +39 -0
- package/examples/js/html_download.js +23 -0
- package/examples/js/image_download.js +36 -0
- package/examples/js/markdown_download.js +23 -0
- package/examples/js/playwright_example.js +23 -0
- package/examples/python/html_download.py +15 -0
- package/examples/python/image_download.py +20 -0
- package/examples/python/markdown_download.py +15 -0
- package/examples/python/playwright_example.py +22 -0
- package/jest.config.mjs +18 -0
- package/package.json +83 -0
- package/scripts/changeset-version.mjs +38 -0
- package/scripts/create-github-release.mjs +93 -0
- package/scripts/create-manual-changeset.mjs +88 -0
- package/scripts/format-github-release.mjs +83 -0
- package/scripts/format-release-notes.mjs +218 -0
- package/scripts/instant-version-bump.mjs +121 -0
- package/scripts/publish-to-npm.mjs +128 -0
- package/scripts/setup-npm.mjs +37 -0
- package/scripts/validate-changeset.mjs +106 -0
- package/scripts/version-and-commit.mjs +237 -0
- package/src/browser.js +207 -0
- package/src/fetch.js +38 -0
- package/src/html.js +64 -0
- package/src/image.js +41 -0
- package/src/index.js +55 -0
- package/src/lib.js +330 -0
- package/src/markdown.js +17 -0
- package/src/stream.js +50 -0
- package/tests/e2e/docker.test.js +148 -0
- package/tests/e2e/process.test.js +117 -0
- package/tests/integration/browser-engines.test.js +128 -0
- package/tests/jest.setup.mjs +7 -0
- package/tests/mock/index.test.js +223 -0
- package/tests/unit/browser.test.js +136 -0
- package/tests/unit/cli.test.js +151 -0
- package/tests/unit/convertRelativeUrls.test.js +34 -0
- package/tests/unit/html2md.test.js +610 -0
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
import { convertHtmlToMarkdown } from '../../src/lib.js';
|
|
2
|
+
|
|
3
|
+
describe('convertHtmlToMarkdown', () => {
|
|
4
|
+
it('removes empty links and anchor headings', () => {
|
|
5
|
+
const html = `
|
|
6
|
+
<a href="/http-api/authorization"></a>
|
|
7
|
+
<a href="/webhooks/authorization"></a>
|
|
8
|
+
<a href="/api-reference/http-api"></a>
|
|
9
|
+
<h3></h3>
|
|
10
|
+
<a href="#quick-start"></a>
|
|
11
|
+
<h3>Quick start</h3>
|
|
12
|
+
`;
|
|
13
|
+
const md = convertHtmlToMarkdown(html);
|
|
14
|
+
// Should not contain empty []() links or [](#anchor) or empty headings
|
|
15
|
+
expect(md).not.toMatch(/\[\s*\]\([^)]*\)/);
|
|
16
|
+
expect(md).not.toMatch(/#+\s*$/m);
|
|
17
|
+
expect(md).not.toMatch(/\[\s*\]\(#.*\)/);
|
|
18
|
+
// Should contain the real heading
|
|
19
|
+
expect(md).toMatch(/### Quick start/);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('removes empty links in complex content', () => {
|
|
23
|
+
const html = `
|
|
24
|
+
<div>
|
|
25
|
+
<a href="/foo"></a>
|
|
26
|
+
<a href="/bar">Bar</a>
|
|
27
|
+
<a href="#anchor"></a>
|
|
28
|
+
<h2></h2>
|
|
29
|
+
<h2>Title</h2>
|
|
30
|
+
</div>
|
|
31
|
+
`;
|
|
32
|
+
const md = convertHtmlToMarkdown(html);
|
|
33
|
+
expect(md).not.toMatch(/\[\s*\]\([^)]*\)/);
|
|
34
|
+
expect(md).toMatch(/\[Bar\]\(\/bar\)/);
|
|
35
|
+
expect(md).toMatch(/## Title/);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('removes empty links with only whitespace', () => {
|
|
39
|
+
const html = `
|
|
40
|
+
<a href="/foo"> </a>
|
|
41
|
+
<a href="/bar">\n\t</a>
|
|
42
|
+
<a href="#anchor"> </a>
|
|
43
|
+
`;
|
|
44
|
+
const md = convertHtmlToMarkdown(html);
|
|
45
|
+
expect(md).not.toMatch(/\[\s*\]\([^)]*\)/);
|
|
46
|
+
expect(md).not.toMatch(/\[\s*\]\(#.*\)/);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('removes empty links with only child elements', () => {
|
|
50
|
+
const html = `
|
|
51
|
+
<a href="/foo"><span></span></a>
|
|
52
|
+
<a href="/bar"><div></div></a>
|
|
53
|
+
<a href="#anchor"><span> </span></a>
|
|
54
|
+
<a href="/baz"><img src='x.png'></a>
|
|
55
|
+
<a href="/qux"><span>\n</span></a>
|
|
56
|
+
<a href="/keep">Text<span>child</span></a>
|
|
57
|
+
`;
|
|
58
|
+
const md = convertHtmlToMarkdown(html);
|
|
59
|
+
expect(md).not.toMatch(/\[\s*\]\([^)]*\)/);
|
|
60
|
+
expect(md).not.toMatch(/\[\s*\]\(#.*\)/);
|
|
61
|
+
expect(md).toMatch(/\[Textchild\]\(\/keep\)/);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('removes headings with only whitespace', () => {
|
|
65
|
+
const html = `
|
|
66
|
+
<h2> </h2>
|
|
67
|
+
<h3>\n\t</h3>
|
|
68
|
+
<h4>\u00A0</h4>
|
|
69
|
+
<h2>Valid Heading</h2>
|
|
70
|
+
`;
|
|
71
|
+
const md = convertHtmlToMarkdown(html);
|
|
72
|
+
expect(md).not.toMatch(/#+\s*$/m);
|
|
73
|
+
expect(md).toMatch(/## Valid Heading/);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('converts relative links to absolute if baseUrl is provided', () => {
|
|
77
|
+
const html = `
|
|
78
|
+
<a href="/foo">Foo</a>
|
|
79
|
+
<img src="/bar.png" alt="Bar">
|
|
80
|
+
<a href="https://external.com">External</a>
|
|
81
|
+
`;
|
|
82
|
+
const md = convertHtmlToMarkdown(html, 'https://example.com/base/');
|
|
83
|
+
expect(md).toMatch(/\[Foo\]\(https:\/\/example.com\/foo\)/);
|
|
84
|
+
expect(md).toMatch(/!\[Bar\]\(https:\/\/example.com\/bar.png\)/);
|
|
85
|
+
expect(md).toMatch(/\[External\]\(https:\/\/external.com\/?\)/);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('does not change links if no baseUrl is provided', () => {
|
|
89
|
+
const html = `
|
|
90
|
+
<a href="/foo">Foo</a>
|
|
91
|
+
<img src="/bar.png" alt="Bar">
|
|
92
|
+
`;
|
|
93
|
+
const md = convertHtmlToMarkdown(html);
|
|
94
|
+
expect(md).toMatch(/\[Foo\]\(\/foo\)/);
|
|
95
|
+
expect(md).toMatch(/!\[Bar\]\(\/bar.png\)/);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('converts ARIA role table to Markdown table', () => {
|
|
99
|
+
const html = `
|
|
100
|
+
<div
|
|
101
|
+
role="table"
|
|
102
|
+
aria-label="Semantic Elements"
|
|
103
|
+
aria-describedby="semantic_elements_table_desc"
|
|
104
|
+
aria-rowcount="81">
|
|
105
|
+
<div id="semantic_elements_table_desc">
|
|
106
|
+
Semantic Elements to use instead of ARIA's roles
|
|
107
|
+
</div>
|
|
108
|
+
<div role="rowgroup">
|
|
109
|
+
<div role="row">
|
|
110
|
+
<span role="columnheader" aria-sort="none">ARIA Role</span>
|
|
111
|
+
<span role="columnheader" aria-sort="none">Semantic Element</span>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<div role="rowgroup">
|
|
115
|
+
<div role="row" aria-rowindex="11">
|
|
116
|
+
<span role="cell">header</span>
|
|
117
|
+
<span role="cell">h1</span>
|
|
118
|
+
</div>
|
|
119
|
+
<div role="row" aria-rowindex="16">
|
|
120
|
+
<span role="cell">header</span>
|
|
121
|
+
<span role="cell">h6</span>
|
|
122
|
+
</div>
|
|
123
|
+
<div role="row" aria-rowindex="18">
|
|
124
|
+
<span role="cell">rowgroup</span>
|
|
125
|
+
<span role="cell">thead</span>
|
|
126
|
+
</div>
|
|
127
|
+
<div role="row" aria-rowindex="24">
|
|
128
|
+
<span role="cell">term</span>
|
|
129
|
+
<span role="cell">dt</span>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
`;
|
|
134
|
+
const md = convertHtmlToMarkdown(html);
|
|
135
|
+
// Should contain a Markdown table header
|
|
136
|
+
expect(md).toMatch(/\|\s*ARIA Role\s*\|\s*Semantic Element\s*\|/);
|
|
137
|
+
// Should contain the separator row
|
|
138
|
+
expect(md).toMatch(/\|\s*-+\s*\|\s*-+\s*\|/);
|
|
139
|
+
// Should contain all data rows
|
|
140
|
+
expect(md).toMatch(/\|\s*header\s*\|\s*h1\s*\|/);
|
|
141
|
+
expect(md).toMatch(/\|\s*header\s*\|\s*h6\s*\|/);
|
|
142
|
+
expect(md).toMatch(/\|\s*rowgroup\s*\|\s*thead\s*\|/);
|
|
143
|
+
expect(md).toMatch(/\|\s*term\s*\|\s*dt\s*\|/);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('converts a regular HTML table to Markdown table', () => {
|
|
147
|
+
const html = `
|
|
148
|
+
<table>
|
|
149
|
+
<caption>Sample Table</caption>
|
|
150
|
+
<thead>
|
|
151
|
+
<tr>
|
|
152
|
+
<th>Header 1</th>
|
|
153
|
+
<th>Header 2</th>
|
|
154
|
+
</tr>
|
|
155
|
+
</thead>
|
|
156
|
+
<tbody>
|
|
157
|
+
<tr>
|
|
158
|
+
<td>Cell 1</td>
|
|
159
|
+
<td>Cell 2</td>
|
|
160
|
+
</tr>
|
|
161
|
+
<tr>
|
|
162
|
+
<td>Cell 3</td>
|
|
163
|
+
<td>Cell 4</td>
|
|
164
|
+
</tr>
|
|
165
|
+
</tbody>
|
|
166
|
+
</table>
|
|
167
|
+
`;
|
|
168
|
+
const md = convertHtmlToMarkdown(html);
|
|
169
|
+
// Should contain a Markdown table header
|
|
170
|
+
expect(md).toMatch(/\|\s*Header 1\s*\|\s*Header 2\s*\|/);
|
|
171
|
+
// Should contain the separator row
|
|
172
|
+
expect(md).toMatch(/\|\s*-+\s*\|\s*-+\s*\|/);
|
|
173
|
+
// Should contain all data rows
|
|
174
|
+
expect(md).toMatch(/\|\s*Cell 1\s*\|\s*Cell 2\s*\|/);
|
|
175
|
+
expect(md).toMatch(/\|\s*Cell 3\s*\|\s*Cell 4\s*\|/);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('handles empty tables gracefully', () => {
|
|
179
|
+
const html = `
|
|
180
|
+
<table>
|
|
181
|
+
<thead>
|
|
182
|
+
<tr>
|
|
183
|
+
<th></th>
|
|
184
|
+
<th></th>
|
|
185
|
+
</tr>
|
|
186
|
+
</thead>
|
|
187
|
+
<tbody>
|
|
188
|
+
<tr>
|
|
189
|
+
<td></td>
|
|
190
|
+
<td></td>
|
|
191
|
+
</tr>
|
|
192
|
+
</tbody>
|
|
193
|
+
</table>
|
|
194
|
+
`;
|
|
195
|
+
const md = convertHtmlToMarkdown(html);
|
|
196
|
+
// Should not throw an error
|
|
197
|
+
// Accept the actual output for an empty table (2 columns, empty header and row)
|
|
198
|
+
expect(md.trim()).toBe('| | |\n| --- | --- |\n| | |');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('handles specific ARIA table example', () => {
|
|
202
|
+
const html = `
|
|
203
|
+
<div
|
|
204
|
+
class="mx-auto w-full decoration-primary/6 max-w-3xl page-api-block:ml-0 table_tableWrapper__zr7LC"
|
|
205
|
+
>
|
|
206
|
+
<div role="table" class="flex flex-col">
|
|
207
|
+
<div
|
|
208
|
+
role="rowgroup"
|
|
209
|
+
class="w-full table_rowGroup__IKtSP straight-corners:rounded-none"
|
|
210
|
+
>
|
|
211
|
+
<div role="row" class="flex w-full">
|
|
212
|
+
<div
|
|
213
|
+
role="columnheader"
|
|
214
|
+
class="table_columnHeader__PGmsy text-left"
|
|
215
|
+
title="Attribute"
|
|
216
|
+
style="width: 181px; min-width: 181px"
|
|
217
|
+
>
|
|
218
|
+
Attribute
|
|
219
|
+
</div>
|
|
220
|
+
<div
|
|
221
|
+
role="columnheader"
|
|
222
|
+
class="table_columnHeader__PGmsy text-left"
|
|
223
|
+
title="Type"
|
|
224
|
+
style="width: 110px; min-width: 110px"
|
|
225
|
+
>
|
|
226
|
+
Type
|
|
227
|
+
</div>
|
|
228
|
+
<div
|
|
229
|
+
role="columnheader"
|
|
230
|
+
class="table_columnHeader__PGmsy text-left"
|
|
231
|
+
title="Required"
|
|
232
|
+
style="width: 104px; min-width: 104px"
|
|
233
|
+
>
|
|
234
|
+
Required
|
|
235
|
+
</div>
|
|
236
|
+
<div
|
|
237
|
+
role="columnheader"
|
|
238
|
+
class="table_columnHeader__PGmsy text-left"
|
|
239
|
+
title="Description"
|
|
240
|
+
style="width: clamp(100px, 100% - 395px, 100%); min-width: 100px"
|
|
241
|
+
>
|
|
242
|
+
Description
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
<div role="rowgroup" class="flex flex-col w-full [&>*+*]:border-t">
|
|
247
|
+
<div class="table_row__LpfCG" role="row">
|
|
248
|
+
<div
|
|
249
|
+
role="cell"
|
|
250
|
+
class="table_cell__X_gFM"
|
|
251
|
+
style="width: 181px; min-width: 181px"
|
|
252
|
+
>
|
|
253
|
+
<div
|
|
254
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
255
|
+
>
|
|
256
|
+
<p class="mx-auto decoration-primary/6 w-full max-w-[unset]">
|
|
257
|
+
amount
|
|
258
|
+
</p>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
<div
|
|
262
|
+
role="cell"
|
|
263
|
+
class="table_cell__X_gFM"
|
|
264
|
+
style="width: 110px; min-width: 110px"
|
|
265
|
+
>
|
|
266
|
+
<div
|
|
267
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
268
|
+
>
|
|
269
|
+
<p class="mx-auto decoration-primary/6 w-full max-w-[unset]">
|
|
270
|
+
decimal
|
|
271
|
+
</p>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
<div
|
|
275
|
+
role="cell"
|
|
276
|
+
class="table_cell__X_gFM"
|
|
277
|
+
style="width: 104px; min-width: 104px"
|
|
278
|
+
>
|
|
279
|
+
<div
|
|
280
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
281
|
+
>
|
|
282
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">yes</p>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
<div
|
|
286
|
+
role="cell"
|
|
287
|
+
class="table_cell__X_gFM"
|
|
288
|
+
style="
|
|
289
|
+
width: clamp(100px, 100% - 395px, 100%);
|
|
290
|
+
min-width: clamp(100px, 100% - 395px, 100%);
|
|
291
|
+
"
|
|
292
|
+
>
|
|
293
|
+
<div
|
|
294
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
295
|
+
>
|
|
296
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
297
|
+
order amount
|
|
298
|
+
</p>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
<div class="table_row__LpfCG" role="row">
|
|
303
|
+
<div
|
|
304
|
+
role="cell"
|
|
305
|
+
class="table_cell__X_gFM"
|
|
306
|
+
style="width: 181px; min-width: 181px"
|
|
307
|
+
>
|
|
308
|
+
<div
|
|
309
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
310
|
+
>
|
|
311
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
312
|
+
currency_id
|
|
313
|
+
</p>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
<div
|
|
317
|
+
role="cell"
|
|
318
|
+
class="table_cell__X_gFM"
|
|
319
|
+
style="width: 110px; min-width: 110px"
|
|
320
|
+
>
|
|
321
|
+
<div
|
|
322
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
323
|
+
>
|
|
324
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
325
|
+
string
|
|
326
|
+
</p>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
<div
|
|
330
|
+
role="cell"
|
|
331
|
+
class="table_cell__X_gFM"
|
|
332
|
+
style="width: 104px; min-width: 104px"
|
|
333
|
+
>
|
|
334
|
+
<div
|
|
335
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
336
|
+
>
|
|
337
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">yes</p>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
<div
|
|
341
|
+
role="cell"
|
|
342
|
+
class="table_cell__X_gFM"
|
|
343
|
+
style="
|
|
344
|
+
width: clamp(100px, 100% - 395px, 100%);
|
|
345
|
+
min-width: clamp(100px, 100% - 395px, 100%);
|
|
346
|
+
"
|
|
347
|
+
>
|
|
348
|
+
<div
|
|
349
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
350
|
+
>
|
|
351
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
352
|
+
order currency id
|
|
353
|
+
</p>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
</div>
|
|
357
|
+
<div class="table_row__LpfCG" role="row">
|
|
358
|
+
<div
|
|
359
|
+
role="cell"
|
|
360
|
+
class="table_cell__X_gFM"
|
|
361
|
+
style="width: 181px; min-width: 181px"
|
|
362
|
+
>
|
|
363
|
+
<div
|
|
364
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
365
|
+
>
|
|
366
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
367
|
+
network
|
|
368
|
+
</p>
|
|
369
|
+
</div>
|
|
370
|
+
</div>
|
|
371
|
+
<div
|
|
372
|
+
role="cell"
|
|
373
|
+
class="table_cell__X_gFM"
|
|
374
|
+
style="width: 110px; min-width: 110px"
|
|
375
|
+
>
|
|
376
|
+
<div
|
|
377
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
378
|
+
>
|
|
379
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
380
|
+
string
|
|
381
|
+
</p>
|
|
382
|
+
</div>
|
|
383
|
+
</div>
|
|
384
|
+
<div
|
|
385
|
+
role="cell"
|
|
386
|
+
class="table_cell__X_gFM"
|
|
387
|
+
style="width: 104px; min-width: 104px"
|
|
388
|
+
>
|
|
389
|
+
<div
|
|
390
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
391
|
+
>
|
|
392
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">yes</p>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
<div
|
|
396
|
+
role="cell"
|
|
397
|
+
class="table_cell__X_gFM"
|
|
398
|
+
style="
|
|
399
|
+
width: clamp(100px, 100% - 395px, 100%);
|
|
400
|
+
min-width: clamp(100px, 100% - 395px, 100%);
|
|
401
|
+
"
|
|
402
|
+
>
|
|
403
|
+
<div
|
|
404
|
+
class="blocks w-full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
405
|
+
>
|
|
406
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
407
|
+
currency network
|
|
408
|
+
</p>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
<div class="table_row__LpfCG" role="row">
|
|
413
|
+
<div
|
|
414
|
+
role="cell"
|
|
415
|
+
class="table_cell__X_gFM"
|
|
416
|
+
style="width: 181px; min-width: 181px"
|
|
417
|
+
>
|
|
418
|
+
<div
|
|
419
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
420
|
+
>
|
|
421
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
422
|
+
external_order_id
|
|
423
|
+
</p>
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
426
|
+
<div
|
|
427
|
+
role="cell"
|
|
428
|
+
class="table_cell__X_gFM"
|
|
429
|
+
style="width: 110px; min-width: 110px"
|
|
430
|
+
>
|
|
431
|
+
<div
|
|
432
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
433
|
+
>
|
|
434
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
435
|
+
string
|
|
436
|
+
</p>
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
<div
|
|
440
|
+
role="cell"
|
|
441
|
+
class="table_cell__X_gFM"
|
|
442
|
+
style="width: 104px; min-width: 104px"
|
|
443
|
+
>
|
|
444
|
+
<div
|
|
445
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
446
|
+
>
|
|
447
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">no</p>
|
|
448
|
+
</div>
|
|
449
|
+
</div>
|
|
450
|
+
<div
|
|
451
|
+
role="cell"
|
|
452
|
+
class="table_cell__X_gFM"
|
|
453
|
+
style="
|
|
454
|
+
width: clamp(100px, 100% - 395px, 100%);
|
|
455
|
+
min-width: clamp(100px, 100% - 395px, 100%);
|
|
456
|
+
"
|
|
457
|
+
>
|
|
458
|
+
<div
|
|
459
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
460
|
+
>
|
|
461
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
462
|
+
additional external invoice id
|
|
463
|
+
</p>
|
|
464
|
+
</div>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
<div class="table_row__LpfCG" role="row">
|
|
468
|
+
<div
|
|
469
|
+
role="cell"
|
|
470
|
+
class="table_cell__X_gFM"
|
|
471
|
+
style="width: 181px; min-width: 181px"
|
|
472
|
+
>
|
|
473
|
+
<div
|
|
474
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
475
|
+
>
|
|
476
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
477
|
+
email
|
|
478
|
+
</p>
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
<div
|
|
482
|
+
role="cell"
|
|
483
|
+
class="table_cell__X_gFM"
|
|
484
|
+
style="width: 110px; min-width: 110px"
|
|
485
|
+
>
|
|
486
|
+
<div
|
|
487
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
488
|
+
>
|
|
489
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
490
|
+
string
|
|
491
|
+
</p>
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
<div
|
|
495
|
+
role="cell"
|
|
496
|
+
class="table_cell__X_gFM"
|
|
497
|
+
style="width: 104px; min-width: 104px"
|
|
498
|
+
>
|
|
499
|
+
<div
|
|
500
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
501
|
+
>
|
|
502
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">no</p>
|
|
503
|
+
</div>
|
|
504
|
+
</div>
|
|
505
|
+
<div
|
|
506
|
+
role="cell"
|
|
507
|
+
class="table_cell__X_gFM"
|
|
508
|
+
style="
|
|
509
|
+
width: clamp(100px, 100% - 395px, 100%);
|
|
510
|
+
min-width: clamp(100px, 100% - 395px, 100%);
|
|
511
|
+
"
|
|
512
|
+
>
|
|
513
|
+
<div
|
|
514
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
515
|
+
>
|
|
516
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
517
|
+
end users email
|
|
518
|
+
</p>
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
<div class="table_row__LpfCG" role="row">
|
|
523
|
+
<div
|
|
524
|
+
role="cell"
|
|
525
|
+
class="table_cell__X_gFM"
|
|
526
|
+
style="width: 181px; min-width: 181px"
|
|
527
|
+
>
|
|
528
|
+
<div
|
|
529
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
530
|
+
>
|
|
531
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
532
|
+
description
|
|
533
|
+
</p>
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
<div
|
|
537
|
+
role="cell"
|
|
538
|
+
class="table_cell__X_gFM"
|
|
539
|
+
style="width: 110px; min-width: 110px"
|
|
540
|
+
>
|
|
541
|
+
<div
|
|
542
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
543
|
+
>
|
|
544
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
545
|
+
string
|
|
546
|
+
</p>
|
|
547
|
+
</div>
|
|
548
|
+
</div>
|
|
549
|
+
<div
|
|
550
|
+
role="cell"
|
|
551
|
+
class="table_cell__X_gFM"
|
|
552
|
+
style="width: 104px; min-width: 104px"
|
|
553
|
+
>
|
|
554
|
+
<div
|
|
555
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
556
|
+
>
|
|
557
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">no</p>
|
|
558
|
+
</div>
|
|
559
|
+
</div>
|
|
560
|
+
<div
|
|
561
|
+
role="cell"
|
|
562
|
+
class="table_cell__X_gFM"
|
|
563
|
+
style="
|
|
564
|
+
width: clamp(100px, 100% - 395px, 100%);
|
|
565
|
+
min-width: clamp(100px, 100% - 395px, 100%);
|
|
566
|
+
"
|
|
567
|
+
>
|
|
568
|
+
<div
|
|
569
|
+
class="blocks w_full space-y-2 lg:space-y-3 leading-normal self-center [&_*]:text-left text-left"
|
|
570
|
+
>
|
|
571
|
+
<p class="mx-auto decoration-primary/6 w_full max-w-[unset]">
|
|
572
|
+
order description
|
|
573
|
+
</p>
|
|
574
|
+
</div>
|
|
575
|
+
</div>
|
|
576
|
+
</div>
|
|
577
|
+
</div>
|
|
578
|
+
</div>
|
|
579
|
+
</div>
|
|
580
|
+
`;
|
|
581
|
+
|
|
582
|
+
const md = convertHtmlToMarkdown(html);
|
|
583
|
+
// Should contain a Markdown table header
|
|
584
|
+
expect(md).toMatch(
|
|
585
|
+
/\|\s*Attribute\s*\|\s*Type\s*\|\s*Required\s*\|\s*Description\s*\|/
|
|
586
|
+
);
|
|
587
|
+
// Should contain the separator row
|
|
588
|
+
expect(md).toMatch(/\|\s*-+\s*\|\s*-+\s*\|\s*-+\s*\|\s*-+\s*\|/);
|
|
589
|
+
// Should contain all data rows
|
|
590
|
+
// Accept any number of backslashes before underscores (Turndown may escape as \\_)
|
|
591
|
+
expect(md).toMatch(
|
|
592
|
+
/\|\s*amount\s*\|\s*decimal\s*\|\s*yes\s*\|\s*order amount\s*\|/
|
|
593
|
+
);
|
|
594
|
+
expect(md).toMatch(
|
|
595
|
+
/\|\s*currency(?:\\*)_id\s*\|\s*string\s*\|\s*yes\s*\|\s*order currency id\s*\|/
|
|
596
|
+
);
|
|
597
|
+
expect(md).toMatch(
|
|
598
|
+
/\|\s*network\s*\|\s*string\s*\|\s*yes\s*\|\s*currency network\s*\|/
|
|
599
|
+
);
|
|
600
|
+
expect(md).toMatch(
|
|
601
|
+
/\|\s*external(?:\\*)_order(?:\\*)_id\s*\|\s*string\s*\|\s*no\s*\|\s*additional external invoice id\s*\|/
|
|
602
|
+
);
|
|
603
|
+
expect(md).toMatch(
|
|
604
|
+
/\|\s*email\s*\|\s*string\s*\|\s*no\s*\|\s*end users email\s*\|/
|
|
605
|
+
);
|
|
606
|
+
expect(md).toMatch(
|
|
607
|
+
/\|\s*description\s*\|\s*string\s*\|\s*no\s*\|\s*order description\s*\|/
|
|
608
|
+
);
|
|
609
|
+
});
|
|
610
|
+
});
|