@apify/docusaurus-plugin-typedoc-api 4.2.10 → 4.2.11-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/lib/components/ApiItem.js +97 -2
  2. package/lib/components/ApiItem.js.map +1 -1
  3. package/lib/components/ApiPage.js +0 -3
  4. package/lib/components/ApiPage.js.map +1 -1
  5. package/lib/components/Markdown.js +0 -2
  6. package/lib/components/Markdown.js.map +1 -1
  7. package/lib/components/MemberGetterSetter.js +0 -1
  8. package/lib/components/MemberGetterSetter.js.map +1 -1
  9. package/lib/components/MemberSignatureBody.js +2 -7
  10. package/lib/components/MemberSignatureBody.js.map +1 -1
  11. package/lib/components/Reflection.js +0 -1
  12. package/lib/components/Reflection.js.map +1 -1
  13. package/lib/components/SourceLink.js +5 -1
  14. package/lib/components/SourceLink.js.map +1 -1
  15. package/lib/components/Type.js +2 -3
  16. package/lib/components/Type.js.map +1 -1
  17. package/lib/index.js +23 -10
  18. package/lib/index.js.map +1 -1
  19. package/lib/plugin/data.js +1 -9
  20. package/lib/plugin/data.js.map +1 -1
  21. package/lib/plugin/python/consts.js +47 -0
  22. package/lib/plugin/python/consts.js.map +1 -0
  23. package/lib/plugin/python/index.js +36 -0
  24. package/lib/plugin/python/index.js.map +1 -0
  25. package/lib/plugin/python/inheritance.js +71 -0
  26. package/lib/plugin/python/inheritance.js.map +1 -0
  27. package/lib/plugin/python/packageVersions.js +46 -0
  28. package/lib/plugin/python/packageVersions.js.map +1 -0
  29. package/lib/plugin/python/transformation.js +359 -0
  30. package/lib/plugin/python/transformation.js.map +1 -0
  31. package/lib/plugin/python/type-parsing/index.js +79 -0
  32. package/lib/plugin/python/type-parsing/index.js.map +1 -0
  33. package/lib/plugin/python/types.js +2 -0
  34. package/lib/plugin/python/types.js.map +1 -0
  35. package/lib/plugin/python/utils.js +106 -0
  36. package/lib/plugin/python/utils.js.map +1 -0
  37. package/lib/plugin/structure/0.23.js +0 -2
  38. package/lib/plugin/structure/0.23.js.map +1 -1
  39. package/lib/utils/icons.js +1 -2
  40. package/lib/utils/icons.js.map +1 -1
  41. package/lib/utils/reexports.js +96 -0
  42. package/lib/utils/reexports.js.map +1 -0
  43. package/package.json +5 -3
  44. package/src/components/ApiItem.tsx +103 -9
  45. package/src/components/ApiItemLayout.tsx +4 -2
  46. package/src/components/ApiOptionsLayout.tsx +18 -16
  47. package/src/components/ApiPage.tsx +0 -2
  48. package/src/components/DefaultValue.tsx +0 -1
  49. package/src/components/Flags.tsx +1 -1
  50. package/src/components/Markdown.tsx +0 -1
  51. package/src/components/Member.tsx +19 -17
  52. package/src/components/MemberGetterSetter.tsx +0 -1
  53. package/src/components/MemberSignatureBody.tsx +42 -38
  54. package/src/components/MemberSignatureTitle.tsx +18 -15
  55. package/src/components/Reflection.tsx +1 -1
  56. package/src/components/SourceLink.tsx +6 -8
  57. package/src/components/Type.tsx +6 -14
  58. package/src/components/VersionBanner.tsx +5 -1
  59. package/src/index.ts +39 -9
  60. package/src/plugin/data.ts +6 -12
  61. package/src/plugin/python/consts.ts +50 -0
  62. package/src/plugin/python/docspec-gen/__init__.py +0 -0
  63. package/src/plugin/python/docspec-gen/generate_ast.py +73 -0
  64. package/src/plugin/python/docspec-gen/google_docstring_processor.py +185 -0
  65. package/src/plugin/python/index.ts +47 -0
  66. package/src/plugin/python/inheritance.ts +80 -0
  67. package/src/plugin/python/packageVersions.ts +43 -0
  68. package/src/plugin/python/transformation.ts +444 -0
  69. package/src/plugin/python/type-parsing/index.ts +88 -0
  70. package/src/plugin/python/type-parsing/parse_types.py +82 -0
  71. package/src/plugin/python/types.ts +83 -0
  72. package/src/plugin/python/utils.ts +123 -0
  73. package/src/plugin/structure/0.23.ts +0 -2
  74. package/src/plugin/version.ts +2 -2
  75. package/src/types.ts +9 -0
  76. package/src/utils/icons.ts +4 -3
  77. package/src/utils/reexports.ts +105 -0
@@ -0,0 +1,82 @@
1
+ """
2
+ Given a JSON file containing a list of expressions, this script will parse each expression and output a JSON file containing an object with the parsed expressions.
3
+ Called from transformDocs.js.
4
+
5
+ Accepts one CLI argument: the path to the JSON file containing the expressions to parse.
6
+ """
7
+
8
+ import ast
9
+ import json
10
+ import sys
11
+ import os
12
+
13
+ base_scalar_types = {
14
+ "str",
15
+ "int",
16
+ "float",
17
+ "bool",
18
+ "bytearray",
19
+ "timedelta",
20
+ "None",
21
+ }
22
+
23
+
24
+ def parse_expression(ast_node, full_expression):
25
+ """
26
+ Turns the AST expression object into a typedoc-compliant dict
27
+ """
28
+
29
+ current_node_type = ast_node.__class__.__name__
30
+
31
+ if current_node_type == "BinOp" and ast_node.op.__class__.__name__ == "BitOr":
32
+ return {
33
+ "type": "union",
34
+ "types": [
35
+ parse_expression(ast_node.left, full_expression),
36
+ parse_expression(ast_node.right, full_expression),
37
+ ],
38
+ }
39
+
40
+ if current_node_type == "Tuple":
41
+ return [parse_expression(e, full_expression) for e in ast_node.elts]
42
+
43
+ if current_node_type == "Subscript":
44
+ if "id" in ast_node.value._fields and ast_node.value.id == "Annotated":
45
+ return parse_expression(ast_node.slice.dims[0], full_expression)
46
+
47
+ main_type = parse_expression(ast_node.value, full_expression)
48
+ type_argument = parse_expression(ast_node.slice, full_expression)
49
+
50
+ main_type["typeArguments"] = (
51
+ type_argument if isinstance(type_argument, list) else [type_argument]
52
+ )
53
+ return main_type
54
+
55
+ if current_node_type == "Constant":
56
+ return {"type": "literal", "value": ast_node.value}
57
+
58
+ # If the expression is not one of the types above, we simply print the expression
59
+ return {
60
+ "type": "reference",
61
+ "name": full_expression[ast_node.col_offset : ast_node.end_col_offset],
62
+ }
63
+
64
+
65
+ typedoc_types_path = sys.argv[1]
66
+
67
+ with open(typedoc_types_path, "r") as f:
68
+ typedoc_out = {}
69
+ expressions = json.load(f)
70
+
71
+ for expression in expressions:
72
+ try:
73
+ if typedoc_out.get(expression) is None:
74
+ typedoc_out[expression] = parse_expression(
75
+ ast.parse(expression).body[0].value, expression
76
+ )
77
+ except Exception as e:
78
+ print(f"Invalid expression encountered while parsing: {expression}")
79
+ print(f"Error: {e}")
80
+
81
+ with open(f"{os.path.splitext(typedoc_types_path)[0]}-parsed.json", "w") as f:
82
+ f.write(json.dumps(typedoc_out, indent=4))
@@ -0,0 +1,83 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { TYPEDOC_KINDS } from './consts';
3
+
4
+ export type OID = number;
5
+
6
+ export interface TypeDocObject {
7
+ [key: string]: any;
8
+ id: OID;
9
+ name: string;
10
+ kind: number;
11
+ kindString: string;
12
+ decorations?: { name: string; args: string }[];
13
+ children?: TypeDocObject[];
14
+ groups?: { title: string; children: OID[] }[];
15
+ flags: Record<string, boolean>;
16
+ module?: string;
17
+ inheritedFrom?: {
18
+ type: string;
19
+ target: OID;
20
+ name: string;
21
+ };
22
+ comment?: {
23
+ summary: { text: string; kind: 'text' }[];
24
+ blockTags?: { tag: string; content: any[] }[];
25
+ };
26
+ signatures?: TypeDocObject[];
27
+ sources?: {
28
+ fileName: string;
29
+ line: number;
30
+ character: number;
31
+ }[];
32
+ type?: TypeDocType;
33
+ symbolIdMap?: Record<number, { qualifiedName: string; sourceFileName: string }>;
34
+ extendedTypes?: TypeDocType[];
35
+ extendedBy?: TypeDocType[];
36
+ modifiers?: any[];
37
+ parameters?: TypeDocObject[];
38
+ }
39
+
40
+ export interface DocspecObject {
41
+ members: DocspecObject[];
42
+ name: string;
43
+ type: keyof typeof TYPEDOC_KINDS;
44
+ location: {
45
+ filename: string;
46
+ lineno: number;
47
+ };
48
+ decorations?: { name: string; args: string }[];
49
+ bases?: DocspecType[];
50
+ datatype?: DocspecType;
51
+ return_type?: DocspecType;
52
+ value?: any;
53
+ docstring?: { content: string };
54
+ modifiers?: DocspecType[];
55
+ args?: { name: string; type: DocspecType; default_value: any; datatype: DocspecType }[];
56
+ }
57
+
58
+ export interface TypeDocDocstring {
59
+ text: string;
60
+ returns?: string;
61
+ args?: Record<string, string>;
62
+ sections?: Record<string, any[]>[];
63
+ }
64
+
65
+ export interface DocspecDocstring {
66
+ text: string;
67
+ returns?: string;
68
+ args?: { param: string; desc: string }[];
69
+ sections?: Record<string, any[]>[];
70
+ }
71
+
72
+ export type TypeDocType =
73
+ {
74
+ [key: string]: any;
75
+ type: 'reference';
76
+ name: string;
77
+ target?: number;
78
+ } | {
79
+ type: 'literal';
80
+ value: any;
81
+ };
82
+
83
+ export type DocspecType = string;
@@ -0,0 +1,123 @@
1
+ /* eslint-disable sort-keys */
2
+ import { GROUP_ORDER, TYPEDOC_KINDS } from './consts';
3
+ import type { DocspecObject, OID, TypeDocObject } from './types';
4
+
5
+ function* generateOID() {
6
+ let id = 1;
7
+ while (true) {
8
+ yield id++;
9
+ }
10
+ }
11
+
12
+ const oidGenerator = generateOID();
13
+
14
+ /**
15
+ * Returns automatically incrementing OID. Every call to this function will return a new unique OID.
16
+ * @returns {number} The OID.
17
+ */
18
+ export function getOID(): OID {
19
+ return oidGenerator.next().value as OID;
20
+ }
21
+
22
+ /**
23
+ * Given a TypeDoc object, returns the name of the group this object belongs to.
24
+ * @param object The TypeDoc object.
25
+ * @returns The group name and the source of the group name (either 'decorator' or 'predicate').
26
+ */
27
+ export function getGroupName(object: TypeDocObject): {
28
+ groupName: string | undefined;
29
+ source: 'decorator' | 'predicate';
30
+ } {
31
+ if (object.decorations?.some((d) => d.name === 'docs_group')) {
32
+ const parsedGroupName = object.decorations
33
+ .find((d) => d.name === 'docs_group')
34
+ ?.args.slice(2, -2);
35
+
36
+ if (parsedGroupName) {
37
+ return {
38
+ groupName: parsedGroupName,
39
+ source: 'decorator',
40
+ };
41
+ }
42
+ }
43
+
44
+ const groupPredicates: Record<string, (obj: TypeDocObject) => boolean> = {
45
+ 'Scrapy integration': (x) =>
46
+ [
47
+ 'ApifyScheduler',
48
+ 'ActorDatasetPushPipeline',
49
+ 'ApifyHttpProxyMiddleware',
50
+ 'apply_apify_settings',
51
+ ].includes(x.name),
52
+ 'Data structures': (x) =>
53
+ Boolean(['BaseModel', 'TypedDict'].some((base) =>
54
+ (x?.bases as { includes: (x: string) => boolean })?.includes(base),
55
+ ) || x?.decorations?.some((d) => d.name === 'dataclass')),
56
+ Errors: (x) => x.name.toLowerCase().includes('error'),
57
+ Classes: (x) => x.kindString === 'Class',
58
+ 'Main Clients': (x) => ['ApifyClient', 'ApifyClientAsync'].includes(x.name),
59
+ 'Async Resource Clients': (x) => x.name.toLowerCase().includes('async'),
60
+ 'Resource Clients': (x) => x.kindString === 'Class' && x.name.toLowerCase().includes('client'),
61
+ Methods: (x) => x.kindString === 'Method',
62
+ Constructors: (x) => x.kindString === 'Constructor',
63
+ Properties: (x) => x.kindString === 'Property',
64
+ Constants: (x) => x.kindString === 'Enumeration',
65
+ 'Enumeration members': (x) => x.kindString === 'Enumeration Member',
66
+ };
67
+
68
+ const groupName = Object.entries(groupPredicates).find(([_, predicate]) =>
69
+ predicate(object),
70
+ )?.[0];
71
+
72
+ return { groupName, source: 'predicate' };
73
+ }
74
+
75
+ /**
76
+ * Recursively search arbitrary JS object for property `name: 'docs_group'`.
77
+ * @param object
78
+ */
79
+ export function projectUsesDocsGroupDecorator(object: { name: string }): boolean {
80
+ if (object instanceof Object) {
81
+ if (object.name === 'docs_group') {
82
+ return true;
83
+ }
84
+
85
+ for (const key in object) {
86
+ if (projectUsesDocsGroupDecorator(object[key as keyof typeof object] as unknown as { name: string })) {
87
+ return true;
88
+ }
89
+ }
90
+ }
91
+
92
+ return false;
93
+ }
94
+
95
+ /**
96
+ * Returns true if the given member should be hidden from the documentation.
97
+ *
98
+ * A member should be hidden if:
99
+ * - It has a `ignore_docs` decoration.
100
+ *
101
+ * @param member The member to check.
102
+ */
103
+ export function isHidden(member: DocspecObject): boolean {
104
+ return (
105
+ !(member.type in TYPEDOC_KINDS) ||
106
+ member.decorations?.some((d) => d.name === 'ignore_docs') ||
107
+ member.name === 'ignore_docs'
108
+ );
109
+ }
110
+
111
+ /**
112
+ * Comparator for enforcing the documentation groups order (examples of groups in {@link GROUP_ORDER}).
113
+ *
114
+ * The groups are sorted by the order in which they appear in {@link GROUP_ORDER}.
115
+ *
116
+ * This is compatible with the `Array.prototype.sort` method.
117
+ */
118
+ export function groupSort(g1: string, g2: string) {
119
+ if (GROUP_ORDER.includes(g1) && GROUP_ORDER.includes(g2)) {
120
+ return GROUP_ORDER.indexOf(g1) - GROUP_ORDER.indexOf(g2);
121
+ }
122
+ return g1.localeCompare(g2);
123
+ }
@@ -1,5 +1,3 @@
1
- /* eslint-disable no-param-reassign */
2
-
3
1
  import { JSONOutput } from 'typedoc';
4
2
 
5
3
  interface OldComment {
@@ -46,9 +46,9 @@ function createVersionMetadata({
46
46
  const isLast = versionName === lastVersionName;
47
47
  const versionOptions = options.versions[versionName] ?? {};
48
48
  const versionLabel =
49
- versionOptions.label ?? versionName === CURRENT_VERSION_NAME ? 'Next' : versionName;
49
+ (versionOptions.label ?? versionName === CURRENT_VERSION_NAME) ? 'Next' : versionName;
50
50
  let versionPathPart =
51
- versionOptions.path ?? versionName === CURRENT_VERSION_NAME ? 'next' : versionName;
51
+ (versionOptions.path ?? versionName === CURRENT_VERSION_NAME) ? 'next' : versionName;
52
52
 
53
53
  if (isLast) {
54
54
  versionPathPart = '';
package/src/types.ts CHANGED
@@ -21,6 +21,9 @@ export interface DocusaurusPluginTypeDocApiOptions
21
21
  minimal?: boolean;
22
22
  packageJsonName?: string;
23
23
  packages: (PackageConfig | string)[];
24
+ /**
25
+ * @deprecated Use `pythonOptions` and the bundled transformation script instead.
26
+ */
24
27
  pathToCurrentVersionTypedocJSON?: string;
25
28
  projectRoot: string;
26
29
  readmeName?: string;
@@ -33,8 +36,13 @@ export interface DocusaurusPluginTypeDocApiOptions
33
36
 
34
37
  /**
35
38
  * Enables the Python-specific rendering patches.
39
+ * If `pythonOptions` is specified, this is automatically set to `true`.
36
40
  */
37
41
  python: boolean;
42
+ pythonOptions: {
43
+ moduleShortcutsPath?: string;
44
+ pythonModulePath?: string;
45
+ };
38
46
 
39
47
  remarkPlugins: MDXPlugin[];
40
48
  rehypePlugins: MDXPlugin[];
@@ -43,6 +51,7 @@ export interface DocusaurusPluginTypeDocApiOptions
43
51
  disableVersioning?: boolean;
44
52
  includeCurrentVersion?: boolean;
45
53
  routeBasePath?: string;
54
+ reexports: { url: string, group?: string }[];
46
55
  }
47
56
 
48
57
  export interface GlobalData {
@@ -28,10 +28,12 @@ const KIND_ICONS: Record<ReflectionKind, string> = {
28
28
  1_048_576: 'symbol-field', // SetSignature
29
29
  2_097_152: 'symbol-parameter', // TypeAlias
30
30
  4_194_304: 'references', // Reference
31
- 8_388_608: 'references' // a Non-TS document (new in TypeDoc `0.26.0`, unused by `docusaurus-plugin-typedoc-api`)
31
+ 8_388_608: 'references', // a Non-TS document (new in TypeDoc `0.26.0`, unused by `docusaurus-plugin-typedoc-api`)
32
32
  };
33
33
 
34
- export function getKindIcon(kind: ReflectionKind, name: string): string {
34
+ export function getKindIcon(kind: ReflectionKind, name?: string): string | null {
35
+ if (!name) return null;
36
+
35
37
  let icon = KIND_ICONS[kind];
36
38
 
37
39
  // Use event icon when property starts with "on"
@@ -42,7 +44,6 @@ export function getKindIcon(kind: ReflectionKind, name: string): string {
42
44
  return icon;
43
45
  }
44
46
 
45
- // eslint-disable-next-line complexity
46
47
  export function getKindIconColor(kind: ReflectionKind): string {
47
48
  switch (kind) {
48
49
  // Function
@@ -0,0 +1,105 @@
1
+ /* eslint-disable */
2
+ // @ts-nocheck
3
+
4
+ import { load } from "cheerio";
5
+ import fs from "fs";
6
+
7
+ interface TypedocJSONFile {
8
+ children: TypedocJSONFile[];
9
+ groups: { title: string, children: number[] }[];
10
+ }
11
+
12
+ interface ExternalApiItem {
13
+ item: TypedocJSONFile;
14
+ groups: string[];
15
+ }
16
+
17
+ async function loadExternalApiItem(url: string): Promise<ExternalApiItem> {
18
+ console.log(`Loading external API item from ${url}...`);
19
+ const response = await fetch(url);
20
+
21
+ const $ = load(await response.text(), { decodeEntities: false })
22
+ const base64encoded = $('script[type="application/typedoc-data;base64"]')?.first()?.text();
23
+
24
+ if(!base64encoded) return null;
25
+
26
+ const jsonData = atob(base64encoded);
27
+ return JSON.parse(jsonData) as ExternalApiItem;
28
+ }
29
+
30
+ // Recursively find the maximum numerical `id` property in a JS object
31
+ function getMaxId(obj: any) {
32
+ let maxId = 0;
33
+ for (const key in obj) {
34
+ if (typeof obj[key] === 'object') {
35
+ maxId = Math.max(maxId, getMaxId(obj[key]));
36
+ } else if (key === 'id') {
37
+ maxId = Math.max(maxId, obj[key]);
38
+ }
39
+ }
40
+
41
+ return maxId;
42
+ }
43
+
44
+ function incrementIds(obj: any, increment: number): number {
45
+ let max = 0;
46
+ for (const key in obj) {
47
+ if (key === 'children' && Array.isArray(obj[key]) && obj[key].every((c: any) => typeof c === 'number')) {
48
+ obj[key] = obj[key].map((c: number) => c + increment);
49
+
50
+ max = Math.max(max, ...obj[key]);
51
+ } else if (key === 'id' && Number.isInteger(obj[key])) {
52
+ obj[key] += increment;
53
+
54
+ max = Math.max(obj[key], max);
55
+ } else if (obj[key] && typeof obj[key] === 'object') {
56
+ max = Math.max(incrementIds(obj[key], increment), max);
57
+ }
58
+ }
59
+
60
+ return max;
61
+ }
62
+
63
+ export async function injectReexports(typedocJsonFilePath: string, reexports: { url: string, group?: string }[]): Promise<void> {
64
+ const typedocJson: TypedocJSONFile = await import(typedocJsonFilePath) as TypedocJSONFile;
65
+
66
+ let baseId = getMaxId(typedocJson);
67
+
68
+ const externalApiItems = await Promise.all(reexports.map(async ({url, group}) => ({
69
+ externalItem: await loadExternalApiItem(url),
70
+ customGroup: group,
71
+ })));
72
+
73
+ for (const { externalItem, customGroup } of externalApiItems) {
74
+ if (!externalItem) continue;
75
+
76
+ let { item, groups } = externalItem;
77
+
78
+ // Make sure the new item doesn't have any conflicting IDs
79
+ baseId = incrementIds(item, baseId);
80
+
81
+ // Add the new item to the root children
82
+ typedocJson.children.push(item);
83
+
84
+ if (customGroup) {
85
+ groups = [customGroup];
86
+ } else if (groups.length === 0) {
87
+ groups = ['Reexports'];
88
+ }
89
+
90
+ for (const groupName of groups) {
91
+ // Assign the new item into the specified groups
92
+ const reexportsGroup = typedocJson.groups.find(g => g.title === groupName);
93
+
94
+ if (reexportsGroup) {
95
+ reexportsGroup.children.push(item.id);
96
+ } else {
97
+ typedocJson.groups.push({ title: groupName, children: [item.id] });
98
+ }
99
+ }
100
+
101
+ console.log(`Reexported item ${item.name} from ${item.sources[0].fileName} to ${groups.join(', ')}`);
102
+ }
103
+
104
+ fs.writeFileSync(typedocJsonFilePath, JSON.stringify(typedocJson, null, 4));
105
+ }