@mintlify/scraping 4.0.1228 → 4.0.1230

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/scraping",
3
- "version": "4.0.1228",
3
+ "version": "4.0.1230",
4
4
  "description": "Scrape documentation frameworks to Mintlify docs",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -43,7 +43,7 @@
43
43
  "format:check": "oxfmt --check"
44
44
  },
45
45
  "dependencies": {
46
- "@mintlify/common": "1.0.1349",
46
+ "@mintlify/common": "1.0.1350",
47
47
  "fast-xml-parser": "5.7.3",
48
48
  "fs-extra": "11.1.1",
49
49
  "graphql": "16.11.0",
@@ -62,9 +62,9 @@
62
62
  "zod": "3.24.0"
63
63
  },
64
64
  "devDependencies": {
65
- "@mintlify/models": "0.0.389",
65
+ "@mintlify/models": "0.0.390",
66
66
  "@mintlify/ts-config": "2.0.2",
67
- "@mintlify/validation": "0.1.962",
67
+ "@mintlify/validation": "0.1.963",
68
68
  "@tsconfig/recommended": "1.0.2",
69
69
  "@types/hast": "3.0.4",
70
70
  "@types/mdast": "4.0.4",
@@ -87,5 +87,5 @@
87
87
  "optional": true
88
88
  }
89
89
  },
90
- "gitHead": "8ba12109669f80e5d70d3639460a775040ffba54"
90
+ "gitHead": "e929a72c0d7dc12e955ca24554b1a3d6e6171bfa"
91
91
  }
@@ -1,10 +1,19 @@
1
1
  import fse from 'fs-extra';
2
2
  import type { Element, ElementContent, Root as HastRoot, RootContent } from 'hast';
3
+ import { randomUUID } from 'node:crypto';
3
4
  import path from 'node:path';
4
5
 
5
6
  import { htmlToHast } from '../../pipeline/root.js';
6
7
  import { removeHastComments } from '../../utils/hastComments.js';
7
8
  import { hastToMdx, type RewriteLink } from '../convert.js';
9
+ import {
10
+ linkedTokens,
11
+ linkedTypeField,
12
+ sliceTokens,
13
+ topLevelDelimiter,
14
+ trimTokens,
15
+ } from '../linked-tokens.js';
16
+ import { linkedCode, type LinkedToken } from '../mdx.js';
8
17
  import type { SdkNavGroup, SdkPage, SdkReference } from '../types.js';
9
18
 
10
19
  type JavadocKind = 'interface' | 'class' | 'enum' | 'record' | 'exception' | 'error' | 'annotation';
@@ -239,11 +248,13 @@ function renderPage(
239
248
  const anchors = collectDetailAnchors(kept);
240
249
  const resolveHref = makeHrefResolver(type, slugByFile, anchors);
241
250
  const signatures: string[] = [];
251
+ const types = new Map<string, string>();
252
+ const prefix = `MINTJAVADOC${randomUUID().replaceAll('-', '')}`;
242
253
  for (const node of kept) {
243
254
  pruneChrome(node);
244
255
  unwrapLists(node);
245
256
  resolveLinks(node, resolveHref);
246
- signatures.push(...codifySignatures(node));
257
+ signatures.push(...codifySignatures(node, types, prefix));
247
258
  }
248
259
 
249
260
  const root: HastRoot = { type: 'root', children: kept as RootContent[] };
@@ -253,6 +264,8 @@ function renderPage(
253
264
  .split(`\`\`\`\n${signature}\n\`\`\``)
254
265
  .join(`\`\`\`java\n${signature}\n\`\`\``);
255
266
  }
267
+ for (const [marker, replacement] of types)
268
+ content = content.replaceAll(marker, () => replacement);
256
269
 
257
270
  return { slug: type.slug, title: type.name, description, tag, content, kind };
258
271
  }
@@ -342,14 +355,21 @@ function unwrapLists(node: Element): void {
342
355
  }
343
356
  }
344
357
 
345
- function codifySignatures(node: Element): string[] {
358
+ function codifySignatures(node: Element, types: Map<string, string>, prefix: string): string[] {
346
359
  const signatures: string[] = [];
360
+ const markers = new Map<Element, string>();
347
361
  visitElements(node, (el) => {
348
362
  if (!hasClass(el, 'member-signature') && !hasClass(el, 'type-signature')) return;
349
363
  const signature = textOf(el)
350
364
  .replace(/\u00a0/g, ' ')
351
365
  .trim();
352
366
  signatures.push(signature);
367
+ const linked = signatureTypes(el);
368
+ if (linked) {
369
+ const marker = `${prefix}TYPES${types.size}END`;
370
+ types.set(marker, linked);
371
+ markers.set(el, marker);
372
+ }
353
373
  el.tagName = 'pre';
354
374
  el.properties = {};
355
375
  el.children = [
@@ -361,9 +381,72 @@ function codifySignatures(node: Element): string[] {
361
381
  },
362
382
  ];
363
383
  });
384
+ insertMarkers(node, markers);
364
385
  return signatures;
365
386
  }
366
387
 
388
+ function insertMarkers(node: Element, markers: Map<Element, string>): void {
389
+ node.children = node.children.flatMap((child): ElementContent[] => {
390
+ if (child.type !== 'element') return [child];
391
+ insertMarkers(child, markers);
392
+ const marker = markers.get(child);
393
+ if (!marker) return [child];
394
+ return [
395
+ child,
396
+ {
397
+ type: 'element',
398
+ tagName: 'p',
399
+ properties: {},
400
+ children: [{ type: 'text', value: marker }],
401
+ },
402
+ ];
403
+ });
404
+ }
405
+
406
+ function signatureTypes(signature: Element): string | undefined {
407
+ const sections: string[] = [];
408
+ const parameters = findElement(signature, (el) => hasClass(el, 'parameters'));
409
+ const fields = parameters ? splitParameters(linkedTokens(parameters.children)) : [];
410
+ if (fields.some((field) => field.tokens.some((token) => token.href))) {
411
+ sections.push(
412
+ '**Parameters**',
413
+ ...fields.map(({ name, tokens }) => linkedTypeField(name, tokens, false))
414
+ );
415
+ }
416
+ const returns = findElement(signature, (el) => hasClass(el, 'return-type'));
417
+ const returnLink = returns ? linkedCode(trimTokens(linkedTokens(returns.children))) : undefined;
418
+ if (returnLink) sections.push(`**${parameters ? 'Returns' : 'Type'}:** ${returnLink}`);
419
+ return sections.length ? sections.join('\n\n') : undefined;
420
+ }
421
+
422
+ type JavadocParameter = { name: string; tokens: LinkedToken[] };
423
+
424
+ function splitParameters(tokens: LinkedToken[]): JavadocParameter[] {
425
+ const text = tokens.map((token) => token.text).join('');
426
+ const open = text.indexOf('(');
427
+ const close = text.lastIndexOf(')');
428
+ if (open === -1 || close <= open) return [];
429
+ const inner = sliceTokens(tokens, open + 1, close);
430
+ const list = inner.map((token) => token.text).join('');
431
+ const parameters: JavadocParameter[] = [];
432
+ let start = 0;
433
+ while (start <= list.length) {
434
+ const comma = topLevelDelimiter(list, ',', start, '<([{', '>)]}');
435
+ const end = comma === -1 ? list.length : comma;
436
+ const parameter = trimTokens(sliceTokens(inner, start, end));
437
+ const value = parameter.map((token) => token.text).join('');
438
+ const name = /([A-Za-z_$][\w$]*)$/.exec(value)?.[1];
439
+ if (name && value.length > name.length) {
440
+ parameters.push({
441
+ name,
442
+ tokens: trimTokens(sliceTokens(parameter, 0, value.length - name.length)),
443
+ });
444
+ }
445
+ start = end + 1;
446
+ }
447
+ return parameters;
448
+ }
449
+
367
450
  function kindFromHeading(scope: Element | HastRoot): JavadocKind {
368
451
  const heading = findElement(scope, (el) => el.tagName === 'h1');
369
452
  const title = heading ? textOf(heading).trim() : '';
@@ -0,0 +1,91 @@
1
+ import type { ElementContent } from 'hast';
2
+
3
+ import { inlineCode, linkedCode, responseField, safeHref, type LinkedToken } from './mdx.js';
4
+
5
+ export function linkedTokens(children: ElementContent[], href?: string): LinkedToken[] {
6
+ const tokens: LinkedToken[] = [];
7
+ for (const child of children) {
8
+ if (child.type === 'text') {
9
+ tokens.push({ text: child.value.replace(/\s+/g, ' '), href });
10
+ } else if (child.type === 'element') {
11
+ let nextHref = href;
12
+ if (child.tagName === 'a' && typeof child.properties.href === 'string') {
13
+ nextHref = safeHref(child.properties.href)?.replace(
14
+ /[\u0000-\u0020\u007f"'()[\]<>`{}\\]/g,
15
+ (character) => `%${character.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0')}`
16
+ );
17
+ }
18
+ tokens.push(...linkedTokens(child.children, nextHref));
19
+ }
20
+ }
21
+ const merged: LinkedToken[] = [];
22
+ for (const token of tokens) {
23
+ const previous = merged.at(-1);
24
+ if (previous && previous.href === token.href) previous.text += token.text;
25
+ else merged.push({ ...token });
26
+ }
27
+ return merged;
28
+ }
29
+
30
+ export function trimTokens(tokens: LinkedToken[]): LinkedToken[] {
31
+ const text = tokens.map((token) => token.text).join('');
32
+ return sliceTokens(tokens, text.length - text.trimStart().length, text.trimEnd().length);
33
+ }
34
+
35
+ export function sliceTokens(tokens: LinkedToken[], start: number, end: number): LinkedToken[] {
36
+ const sliced: LinkedToken[] = [];
37
+ let offset = 0;
38
+ for (const token of tokens) {
39
+ const tokenEnd = offset + token.text.length;
40
+ if (tokenEnd > start && offset < end) {
41
+ sliced.push({
42
+ text: token.text.slice(Math.max(0, start - offset), end - offset),
43
+ href: token.href,
44
+ });
45
+ }
46
+ offset = tokenEnd;
47
+ }
48
+ return sliced;
49
+ }
50
+
51
+ export function topLevelDelimiter(
52
+ text: string,
53
+ delimiter: string,
54
+ start = 0,
55
+ opening = '([{',
56
+ closing = ')]}'
57
+ ): number {
58
+ let depth = 0;
59
+ let quote: string | undefined;
60
+ let escaped = false;
61
+ for (let index = start; index < text.length; index += 1) {
62
+ const character = text[index] ?? '';
63
+ if (escaped) {
64
+ escaped = false;
65
+ } else if (quote) {
66
+ if (character === '\\') escaped = true;
67
+ else if (character === quote) quote = undefined;
68
+ } else if (character === '"' || character === "'") {
69
+ quote = character;
70
+ } else if (opening.includes(character)) {
71
+ depth += 1;
72
+ } else if (closing.includes(character)) {
73
+ depth = Math.max(0, depth - 1);
74
+ } else if (character === delimiter && depth === 0) {
75
+ return index;
76
+ }
77
+ }
78
+ return -1;
79
+ }
80
+
81
+ export function linkedTypeField(name: string, tokens: LinkedToken[], optional: boolean): string {
82
+ const type = tokens.map((token) => token.text).join('');
83
+ const typeHref = tokens.length === 1 ? tokens[0]?.href : undefined;
84
+ let body: string | undefined;
85
+ if (!typeHref || type.length > 80) {
86
+ const linked = linkedCode(tokens);
87
+ if (linked) body = `**Type:** ${linked}`;
88
+ else if (type.length > 80) body = `**Type:** ${inlineCode(type)}`;
89
+ }
90
+ return responseField(name, type, optional, body, typeHref);
91
+ }
@@ -1,7 +1,14 @@
1
1
  import { hastToText } from '@mintlify/common';
2
- import type { Element, ElementContent } from 'hast';
2
+ import type { Element } from 'hast';
3
3
 
4
- import { inlineCode, linkedCode, responseField, safeHref, type LinkedToken } from './mdx.js';
4
+ import {
5
+ linkedTokens,
6
+ linkedTypeField,
7
+ sliceTokens,
8
+ topLevelDelimiter,
9
+ trimTokens,
10
+ } from './linked-tokens.js';
11
+ import { inlineCode, linkedCode, type LinkedToken } from './mdx.js';
5
12
 
6
13
  type DocumentedTypes = {
7
14
  parameters: Map<string, LinkedToken[][]>;
@@ -47,15 +54,7 @@ function renderParameter(parameter: Element, documented: DocumentedTypes): strin
47
54
  if (documented.parameters.get(name)?.some((type) => sameLinkedType(typeTokens, type))) {
48
55
  return undefined;
49
56
  }
50
- const only = typeTokens[0];
51
- const typeHref = typeTokens.length === 1 ? only?.href : undefined;
52
- let body: string | undefined;
53
- if (!typeHref || type.length > 80) {
54
- const linked = linkedCode(typeTokens);
55
- if (linked) body = `**Type:** ${linked}`;
56
- else if (type.length > 80) body = `**Type:** ${inlineCode(type)}`;
57
- }
58
- return responseField(name, type, defaultStart !== -1 || name.startsWith('*'), body, typeHref);
57
+ return linkedTypeField(name, typeTokens, defaultStart !== -1 || name.startsWith('*'));
59
58
  }
60
59
 
61
60
  function documentedTypes(description: Element | undefined): DocumentedTypes {
@@ -147,76 +146,6 @@ function sameLinkedType(left: LinkedToken[], right: LinkedToken[]): boolean {
147
146
  return key(left) === key(right);
148
147
  }
149
148
 
150
- function linkedTokens(children: ElementContent[], href?: string): LinkedToken[] {
151
- const tokens: LinkedToken[] = [];
152
- for (const child of children) {
153
- if (child.type === 'text') {
154
- tokens.push({ text: child.value.replace(/\s+/g, ' '), href });
155
- } else if (child.type === 'element') {
156
- let nextHref = href;
157
- if (child.tagName === 'a' && typeof child.properties.href === 'string') {
158
- nextHref = safeHref(child.properties.href)?.replace(
159
- /[\u0000-\u0020\u007f"'()[\]<>`{}\\]/g,
160
- (character) => `%${character.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0')}`
161
- );
162
- }
163
- tokens.push(...linkedTokens(child.children, nextHref));
164
- }
165
- }
166
- const merged: LinkedToken[] = [];
167
- for (const token of tokens) {
168
- const previous = merged.at(-1);
169
- if (previous && previous.href === token.href) previous.text += token.text;
170
- else merged.push({ ...token });
171
- }
172
- return merged;
173
- }
174
-
175
- function trimTokens(tokens: LinkedToken[]): LinkedToken[] {
176
- const text = tokens.map((token) => token.text).join('');
177
- return sliceTokens(tokens, text.length - text.trimStart().length, text.trimEnd().length);
178
- }
179
-
180
- function sliceTokens(tokens: LinkedToken[], start: number, end: number): LinkedToken[] {
181
- const sliced: LinkedToken[] = [];
182
- let offset = 0;
183
- for (const token of tokens) {
184
- const tokenEnd = offset + token.text.length;
185
- if (tokenEnd > start && offset < end) {
186
- sliced.push({
187
- text: token.text.slice(Math.max(0, start - offset), end - offset),
188
- href: token.href,
189
- });
190
- }
191
- offset = tokenEnd;
192
- }
193
- return sliced;
194
- }
195
-
196
- function topLevelDelimiter(text: string, delimiter: string): number {
197
- let depth = 0;
198
- let quote: string | undefined;
199
- let escaped = false;
200
- for (let index = 0; index < text.length; index += 1) {
201
- const character = text[index];
202
- if (escaped) {
203
- escaped = false;
204
- } else if (quote) {
205
- if (character === '\\') escaped = true;
206
- else if (character === quote) quote = undefined;
207
- } else if (character === '"' || character === "'") {
208
- quote = character;
209
- } else if (character === '(' || character === '[' || character === '{') {
210
- depth += 1;
211
- } else if (character === ')' || character === ']' || character === '}') {
212
- depth = Math.max(0, depth - 1);
213
- } else if (character === delimiter && depth === 0) {
214
- return index;
215
- }
216
- }
217
- return -1;
218
- }
219
-
220
149
  function findElements(node: Element, className: string): Element[] {
221
150
  const elements: Element[] = [];
222
151
  for (const child of node.children) {