1import MDX from '@mdx-js/runtime'; 2import * as React from 'react'; 3 4import * as components from '~/common/translate-markdown'; 5import { Cell, HeaderCell, Row, Table, TableHead } from '~/ui/components/Table'; 6 7type PropertyMeta = { 8 regexHuman?: string; 9 deprecated?: boolean; 10 hidden?: boolean; 11 expoKit?: string; 12 bareWorkflow?: string; 13}; 14 15export type Property = { 16 description?: string; 17 type?: string | string[]; 18 meta?: PropertyMeta; 19 pattern?: string; 20 enum?: string[]; 21 example?: any; 22 exampleString?: string; 23 host?: object; 24 properties?: Record<string, Property>; 25 items?: { 26 properties?: Record<string, Property>; 27 [key: string]: any; 28 }; 29 uniqueItems?: boolean; 30 additionalProperties?: boolean; 31}; 32 33type FormattedProperty = { 34 name: string; 35 description: string; 36 nestingLevel: number; 37}; 38 39type AppConfigSchemaProps = { 40 schema: Record<string, Property>; 41}; 42 43export function formatSchema(rawSchema: [string, Property][]) { 44 const formattedSchema: FormattedProperty[] = []; 45 46 rawSchema.map(property => { 47 appendProperty(formattedSchema, property, 0); 48 }); 49 50 return formattedSchema; 51} 52 53//appends a property and recursivley appends sub-properties 54function appendProperty( 55 formattedSchema: FormattedProperty[], 56 property: [string, Property], 57 _nestingLevel: number 58) { 59 let nestingLevel = _nestingLevel; 60 const propertyKey = property[0]; 61 const propertyValue = property[1]; 62 63 if (propertyValue.meta && (propertyValue.meta.deprecated || propertyValue.meta.hidden)) { 64 return; 65 } 66 67 formattedSchema.push({ 68 name: nestingLevel 69 ? `<subpropertyAnchor level={${nestingLevel}}><inlineCode>${propertyKey}</inlineCode></subpropertyAnchor>` 70 : `<propertyAnchor level={0}><inlineCode>${propertyKey}</inlineCode></propertyAnchor>`, 71 description: createDescription(property), 72 nestingLevel, 73 }); 74 75 nestingLevel++; 76 77 if (propertyValue.properties) { 78 Object.entries(propertyValue.properties).forEach(subproperty => { 79 appendProperty(formattedSchema, subproperty, nestingLevel); 80 }); 81 } //Note: sub-properties are sometimes nested within "items" 82 else if (propertyValue.items && propertyValue.items.properties) { 83 Object.entries(propertyValue.items.properties).forEach(subproperty => { 84 appendProperty(formattedSchema, subproperty, nestingLevel); 85 }); 86 } 87} 88 89export function _getType(propertyValue: Property) { 90 if (propertyValue.enum) { 91 return 'enum'; 92 } else { 93 return propertyValue.type?.toString().replace(',', ' || '); 94 } 95} 96 97export function createDescription(propertyEntry: [string, Property]) { 98 const propertyValue = propertyEntry[1]; 99 100 let propertyDescription = `**(${_getType(propertyValue)})**`; 101 if (propertyValue.description) { 102 propertyDescription += ` - ` + propertyValue.description; 103 } 104 if (propertyValue.meta && propertyValue.meta.regexHuman) { 105 propertyDescription += `\n\n` + propertyValue.meta.regexHuman; 106 } 107 if (propertyValue.meta && propertyValue.meta.expoKit) { 108 propertyDescription += `<expokitDetails>${propertyValue.meta.expoKit}</expokitDetails>`; 109 } 110 if (propertyValue.meta && propertyValue.meta.bareWorkflow) { 111 propertyDescription += `<bareworkflowDetails>${propertyValue.meta.bareWorkflow}</bareworkflowDetails>`; 112 } 113 if (propertyValue.exampleString) { 114 propertyDescription += `\n\n>` + propertyValue.exampleString; 115 } 116 117 return propertyDescription; 118} 119 120const AppConfigSchemaPropertiesTable = ({ schema }: AppConfigSchemaProps) => { 121 const rawSchema = Object.entries(schema); 122 const formattedSchema = formatSchema(rawSchema); 123 124 return ( 125 <Table> 126 <TableHead> 127 <Row> 128 <HeaderCell>Property</HeaderCell> 129 <HeaderCell>Description</HeaderCell> 130 </Row> 131 </TableHead> 132 <tbody> 133 {formattedSchema.map(({ name, description, nestingLevel }, index) => ( 134 <Row key={index}> 135 <Cell fitContent> 136 <div 137 data-testid={name} 138 style={{ 139 marginLeft: `${nestingLevel * 32}px`, 140 display: nestingLevel ? 'list-item' : 'block', 141 listStyleType: nestingLevel % 2 ? 'default' : 'circle', 142 overflowX: 'visible', 143 }}> 144 <MDX components={components}>{name}</MDX> 145 </div> 146 </Cell> 147 <Cell> 148 <MDX components={components}>{description}</MDX> 149 </Cell> 150 </Row> 151 ))} 152 </tbody> 153 </Table> 154 ); 155}; 156 157export default AppConfigSchemaPropertiesTable; 158