Skip to content

Commit

Permalink
fix: place format next to an appropriate type (#202)
Browse files Browse the repository at this point in the history
  • Loading branch information
P0lip committed Jul 28, 2022
1 parent 7139888 commit e85511c
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 31 deletions.
13 changes: 12 additions & 1 deletion src/__fixtures__/formats-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,19 @@
"type": "number",
"format": "float"
},
"count": {
"type": ["integer", "null"],
"format": "int32"
},
"size": {
"type": [
"number",
"string"
],
"format": "byte"
},
"notype": {
"format": "date-time"
"format": "date-time"
},
"permissions": {
"type": [
Expand Down
17 changes: 2 additions & 15 deletions src/components/SchemaRow/SchemaRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,7 @@ import * as React from 'react';
import { COMBINER_NAME_MAP } from '../../consts';
import { useJSVOptionsContext } from '../../contexts';
import { calculateChildrenToShow, isFlattenableNode, isPropertyRequired } from '../../tree';
import {
Caret,
Description,
Format,
getInternalSchemaError,
getValidationsFromSchema,
Types,
Validations,
} from '../shared';
import { Caret, Description, getInternalSchemaError, getValidationsFromSchema, Types, Validations } from '../shared';
import { ChildStack } from '../shared/ChildStack';
import { Properties, useHasProperties } from '../shared/Properties';
import { hoveredNodeAtom, isNodeHoveredAtom } from './state';
Expand Down Expand Up @@ -108,12 +100,7 @@ export const SchemaRow: React.FunctionComponent<SchemaRowProps> = React.memo(({
</Box>
)}

{choices.length === 1 && (
<>
<Types schemaNode={typeToShow} />
<Format schemaNode={typeToShow} />
</>
)}
{choices.length === 1 && <Types schemaNode={typeToShow} />}

{onGoToRef && isReferenceNode(schemaNode) && schemaNode.external ? (
<Box
Expand Down
11 changes: 3 additions & 8 deletions src/components/shared/Format.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { isRegularNode, SchemaNode } from '@stoplight/json-schema-tree';
import { Box } from '@stoplight/mosaic';
import * as React from 'react';

type FormatProps = {
schemaNode: SchemaNode;
format: string;
};

export const Format: React.FunctionComponent<FormatProps> = ({ schemaNode }) => {
if (!isRegularNode(schemaNode) || schemaNode.format === null) {
return null;
}

return <Box as="span" color="muted">{`<${schemaNode.format}>`}</Box>;
export const Format: React.FunctionComponent<FormatProps> = ({ format }) => {
return <Box as="span" color="muted">{`<${format}>`}</Box>;
};
37 changes: 36 additions & 1 deletion src/components/shared/Types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import {
import { Box } from '@stoplight/mosaic';
import * as React from 'react';

import { COMMON_JSON_SCHEMA_AND_OAS_FORMATS } from '../../consts';
import { isPrimitiveArray } from '../../tree';
import { printName } from '../../utils';
import { Format } from './Format';

function shouldRenderName(type: SchemaNodeKind | SchemaCombinerName | '$ref'): boolean {
return type === SchemaNodeKind.Array || type === SchemaNodeKind.Object || type === '$ref';
Expand All @@ -29,6 +32,32 @@ function getTypes(schemaNode: RegularNode): Array<SchemaNodeKind | SchemaCombine
);
}

function getFormats(schemaNode: RegularNode): Partial<Record<SchemaNodeKind, string>> {
const formats: Partial<Record<SchemaNodeKind, string>> = {};

if (isPrimitiveArray(schemaNode) && schemaNode.children[0].format !== null) {
formats.array = schemaNode.children[0].format;
}

if (schemaNode.format === null) {
return formats;
}

const types = getTypes(schemaNode);

for (const type of types) {
if (!(type in COMMON_JSON_SCHEMA_AND_OAS_FORMATS)) continue;

if (COMMON_JSON_SCHEMA_AND_OAS_FORMATS[type].includes(schemaNode.format)) {
formats[type] = schemaNode.format;
return formats;
}
}

formats.string = schemaNode.format;
return formats;
}

export const Types: React.FunctionComponent<{ schemaNode: SchemaNode }> = ({ schemaNode }) => {
if (isReferenceNode(schemaNode)) {
return (
Expand All @@ -43,14 +72,20 @@ export const Types: React.FunctionComponent<{ schemaNode: SchemaNode }> = ({ sch
}

const types = getTypes(schemaNode);
const formats = getFormats(schemaNode);

if (types.length === 0) return null;
if (types.length === 0) {
return formats.string !== void 0 ? <Format format={formats.string} /> : null;
}

const rendered = types.map((type, i, { length }) => (
<React.Fragment key={type}>
<Box as="span" textOverflow="truncate" color="muted">
{shouldRenderName(type) ? printName(schemaNode) ?? type : type}
</Box>

{type in formats ? <Format format={formats[type]} /> : null}

{i < length - 1 && (
<Box as="span" key={`${i}-sep`} color="muted">
{' or '}
Expand Down
17 changes: 11 additions & 6 deletions src/components/shared/__tests__/Format.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { JSONSchema4 } from 'json-schema';
import * as React from 'react';

import { SchemaRow } from '../../SchemaRow';
import { Format } from '../Format';
import { Types } from '../Types';
import { buildTree, findNodeWithPath } from './utils';

describe('Format component', () => {
Expand All @@ -14,23 +14,28 @@ describe('Format component', () => {

it('should render next to a single type', () => {
const wrapper = mount(<SchemaRow schemaNode={findNodeWithPath(tree, ['properties', 'id'])!} nestingLevel={0} />);
expect(wrapper.find(Format)).toHaveText('<float>');
expect(wrapper.find(Types)).toHaveText('number<float>');
wrapper.unmount();
});

it('should render next to an array of types', () => {
it.each`
property | text
${'count'} | ${'integer<int32> or null'}
${'date-of-birth'} | ${'number or string<date-time> or array'}
${'size'} | ${'number<byte> or string'}
`('given $property property, should render next to the appropriate type', ({ property, text }) => {
const wrapper = mount(
<SchemaRow schemaNode={findNodeWithPath(tree, ['properties', 'date-of-birth'])!} nestingLevel={0} />,
<SchemaRow schemaNode={findNodeWithPath(tree, ['properties', property])!} nestingLevel={0} />,
);
expect(wrapper.find(Format)).toHaveText('<date-time>');
expect(wrapper.find(Types)).toHaveText(text);
wrapper.unmount();
});

it('should render even when the type(s) is/are missing', () => {
const wrapper = mount(
<SchemaRow schemaNode={findNodeWithPath(tree, ['properties', 'notype'])!} nestingLevel={0} />,
);
expect(wrapper.find(Format)).toHaveText('<date-time>');
expect(wrapper.find(Types)).toHaveText('<date-time>');
wrapper.unmount();
});
});
8 changes: 8 additions & 0 deletions src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export const COMBINER_PRETTY_NAMES: Readonly<Dictionary<string, SchemaCombinerNa
[SchemaCombinerName.OneOf]: 'or',
};

export const COMMON_JSON_SCHEMA_AND_OAS_FORMATS = {
// strings are omitted because they are the default type to apply format to
number: ['byte', 'int32', 'int64', 'float', 'double'],
get integer() {
return this.number;
},
};

export const NESTING_OFFSET: SpaceVals = 3;

export const CARET_ICON_SIZE = 'sm';
Expand Down

0 comments on commit e85511c

Please sign in to comment.