1import { css } from '@emotion/react';
2import { theme } from '@expo/styleguide';
3import MDX from '@mdx-js/runtime';
4import * as React from 'react';
5
6import * as components from '~/common/translate-markdown';
7
8const STYLES_TABLE = css`
9  font-size: 1rem;
10  margin-top: 24px;
11`;
12
13const STYLES_HEAD = css`
14  background-color: ${theme.background.tertiary};
15`;
16
17const STYLES_DESCRIPTION_CELL = css`
18  word-break: break-word;
19  white-space: break-spaces;
20  padding-bottom: 0.2rem;
21`;
22
23export type Property = {
24  description?: string[];
25  name: string;
26  type?: string | string[];
27  enum?: string[];
28  properties?: Property[];
29};
30
31type FormattedProperty = {
32  name: string;
33  description: string;
34  nestingLevel: number;
35};
36
37export function formatSchema(rawSchema: Property[]) {
38  const formattedSchema: FormattedProperty[] = [];
39
40  rawSchema.map(property => {
41    appendProperty(formattedSchema, property, 0);
42  });
43
44  return formattedSchema;
45}
46
47//appends a property and recursively appends sub-properties
48function appendProperty(
49  formattedSchema: FormattedProperty[],
50  property: Property,
51  _nestingLevel: number
52) {
53  let nestingLevel = _nestingLevel;
54
55  formattedSchema.push({
56    name: nestingLevel
57      ? `<subpropertyAnchor level={${nestingLevel}}><inlineCode>${property.name}</inlineCode></subpropertyAnchor>`
58      : `<propertyAnchor level={0}><inlineCode>${property.name}</inlineCode></propertyAnchor>`,
59    description: createDescription(property),
60    nestingLevel,
61  });
62
63  nestingLevel++;
64
65  if (property.properties) {
66    (property.properties ?? []).forEach(subproperty => {
67      appendProperty(formattedSchema, subproperty, nestingLevel);
68    });
69  }
70}
71
72export function _getType(property: Property) {
73  if (property.enum) {
74    return 'enum';
75  } else {
76    return property.type?.toString().replace(/,/g, ' || ');
77  }
78}
79
80export function createDescription(property: Property) {
81  let propertyDescription = `**(${_getType(property)})**`;
82  if (property.description) {
83    propertyDescription += ` - ` + property.description.join('\n');
84  }
85
86  return propertyDescription;
87}
88
89export default class EasJsonPropertiesTable extends React.Component<{
90  schema: Property[];
91}> {
92  render() {
93    const formattedSchema = formatSchema(this.props.schema);
94
95    return (
96      <table css={STYLES_TABLE}>
97        <thead css={STYLES_HEAD}>
98          <tr>
99            <td>Property</td>
100            <td>Description</td>
101          </tr>
102        </thead>
103        <tbody>
104          {formattedSchema.map((property, index) => {
105            return (
106              <tr key={index}>
107                <td>
108                  <div
109                    data-testid={property.name}
110                    style={{
111                      marginLeft: `${property.nestingLevel * 32}px`,
112                      display: property.nestingLevel ? 'list-item' : 'block',
113                      listStyleType: property.nestingLevel % 2 ? 'default' : 'circle',
114                      width: 'fit-content',
115                      overflowX: 'visible',
116                    }}>
117                    <MDX components={components}>{property.name}</MDX>
118                  </div>
119                </td>
120                <td css={STYLES_DESCRIPTION_CELL}>
121                  <MDX components={components}>{property.description}</MDX>
122                </td>
123              </tr>
124            );
125          })}
126        </tbody>
127      </table>
128    );
129  }
130}
131