xref: /expo/docs/components/plugins/APISection.tsx (revision 1dbbe258)
1import React, { useContext } from 'react';
2
3import DocumentationPageContext from '~/components/DocumentationPageContext';
4import { P } from '~/components/base/paragraph';
5import { GeneratedData } from '~/components/plugins/api/APIDataTypes';
6import APISectionComponents from '~/components/plugins/api/APISectionComponents';
7import APISectionConstants from '~/components/plugins/api/APISectionConstants';
8import APISectionEnums from '~/components/plugins/api/APISectionEnums';
9import APISectionInterfaces from '~/components/plugins/api/APISectionInterfaces';
10import APISectionMethods from '~/components/plugins/api/APISectionMethods';
11import APISectionProps from '~/components/plugins/api/APISectionProps';
12import APISectionTypes from '~/components/plugins/api/APISectionTypes';
13import { TypeDocKind } from '~/components/plugins/api/APISectionUtils';
14
15const LATEST_VERSION = `v${require('~/package.json').version}`;
16
17type Props = {
18  packageName: string;
19  apiName?: string;
20};
21
22const filterDataByKind = (
23  entries: GeneratedData[],
24  kind: TypeDocKind,
25  additionalCondition: (entry: GeneratedData) => boolean = () => true
26) =>
27  entries
28    ? entries.filter((entry: GeneratedData) => entry.kind === kind && additionalCondition(entry))
29    : [];
30
31const isHook = ({ name }: GeneratedData) =>
32  name.startsWith('use') &&
33  // note(simek): hardcode this exception until the method will be renamed
34  name !== 'useSystemBrightnessAsync';
35
36const isListener = ({ name }: GeneratedData) => name.endsWith('Listener');
37
38const renderAPI = (
39  packageName: string,
40  version: string = 'unversioned',
41  apiName?: string
42): JSX.Element => {
43  try {
44    const data = require(`~/public/static/data/${version}/${packageName}.json`).children;
45
46    const methods = filterDataByKind(
47      data,
48      TypeDocKind.Function,
49      entry => !isListener(entry) && !isHook(entry)
50    );
51    const hooks = filterDataByKind(data, TypeDocKind.Function, isHook);
52    const eventSubscriptions = filterDataByKind(data, TypeDocKind.Function, isListener);
53
54    const types = filterDataByKind(
55      data,
56      TypeDocKind.TypeAlias,
57      entry =>
58        !entry.name.includes('Props') &&
59        !!(
60          entry.type.declaration ||
61          entry.type.types ||
62          entry.type.type ||
63          entry.type.typeArguments
64        )
65    );
66
67    const props = filterDataByKind(
68      data,
69      TypeDocKind.TypeAlias,
70      entry =>
71        entry.name.includes('Props') &&
72        (!!entry.type.types || // inheritance
73          !!entry.type.declaration?.children) // no inheritance
74    );
75    const defaultProps = filterDataByKind(
76      data
77        .filter((entry: GeneratedData) => entry.kind === TypeDocKind.Class)
78        .map((entry: GeneratedData) => entry.children)
79        .flat(),
80      TypeDocKind.Property,
81      entry => entry.name === 'defaultProps'
82    )[0];
83
84    const enums = filterDataByKind(data, TypeDocKind.Enum);
85    const interfaces = filterDataByKind(data, TypeDocKind.Interface);
86    const constants = filterDataByKind(
87      data,
88      TypeDocKind.Variable,
89      entry => (entry?.flags?.isConst || false) && entry?.type?.name !== 'React.FC'
90    );
91
92    const components = filterDataByKind(
93      data,
94      TypeDocKind.Variable,
95      entry => entry?.type?.name === 'React.FC'
96    );
97    const componentsPropNames = components.map(component => `${component.name}Props`);
98    const componentsProps = filterDataByKind(props, TypeDocKind.TypeAlias, entry =>
99      componentsPropNames.includes(entry.name)
100    );
101
102    return (
103      <>
104        <APISectionComponents data={components} componentsProps={componentsProps} />
105        <APISectionConstants data={constants} apiName={apiName} />
106        <APISectionMethods data={hooks} header="Hooks" />
107        <APISectionMethods data={methods} apiName={apiName} />
108        <APISectionMethods
109          data={eventSubscriptions}
110          apiName={apiName}
111          header="Event Subscriptions"
112        />
113        {props && !componentsProps.length ? (
114          <APISectionProps data={props} defaultProps={defaultProps} />
115        ) : null}
116        <APISectionTypes data={types} />
117        <APISectionInterfaces data={interfaces} />
118        <APISectionEnums data={enums} />
119      </>
120    );
121  } catch (error) {
122    return <P>No API data file found, sorry!</P>;
123  }
124};
125
126const APISection: React.FC<Props> = ({ packageName, apiName }) => {
127  const { version } = useContext(DocumentationPageContext);
128  const resolvedVersion =
129    version === 'unversioned' ? version : version === 'latest' ? LATEST_VERSION : version;
130  return renderAPI(packageName, resolvedVersion, apiName);
131};
132
133export default APISection;
134