Skip to content

Commit

Permalink
fix: Represent string literal types as unions of a single element (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
pan-kot authored Jul 26, 2024
1 parent 03f2422 commit 72b4157
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 3 deletions.
14 changes: 14 additions & 0 deletions fixtures/components/complex-types/button-group/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';

import { ButtonGroupProps } from './interfaces';

export { ButtonGroupProps };

/**
* Component-level description
*/
export default function ButtonGroup({ variant, items }: ButtonGroupProps) {

Check warning on line 12 in fixtures/components/complex-types/button-group/index.tsx

View workflow job for this annotation

GitHub Actions / build / build

Missing return type on function
return <div className={variant}>{items.length}</div>;
}
20 changes: 20 additions & 0 deletions fixtures/components/complex-types/button-group/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

export interface ButtonGroupProps {
/**
* This is variant
*/
variant: ButtonGroupProps.Variant;

/**
* This is items array
*/
items: ReadonlyArray<ButtonGroupProps.Item>;
}

export namespace ButtonGroupProps {
export type Variant = 'icon';

export type Item = { id: string };
}
12 changes: 12 additions & 0 deletions src/components/build-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ function buildMethodsDefinition(refType?: DeclarationReflection): ComponentFunct
function getPropertyType(type?: Type) {
const typeAlias = schema.types.isReferenceType(type) && (type.reflection as DeclarationReflection | undefined);
const resolvedType = typeAlias ? typeAlias.type : type;

if (schema.types.isUnionType(resolvedType)) {
const subTypes = schema.utils.excludeUndefinedTypeFromUnion(resolvedType);
if (subTypes.length > 1) {
Expand All @@ -84,6 +85,17 @@ function getPropertyType(type?: Type) {
}
}
}
// Treat string literal type as a union with a single element.
if (schema.types.isStringLiteralType(resolvedType)) {
const referenceTypeName = schema.types.isReferenceType(type) ? schema.code.buildType(type) : '';
const declaration = new DeclarationReflection(referenceTypeName, ReflectionKind.TypeLiteral);
declaration.type = resolvedType;
return {
typeName: 'string',
typeDefinition: buildTypeDefinition(declaration),
};
}

return {
typeName: schema.code.buildType(type),
typeDefinition: typeAlias ? buildTypeDefinition(typeAlias) : undefined,
Expand Down
26 changes: 25 additions & 1 deletion src/components/build-type-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { DeclarationReflection, Reflection, SignatureReflection } from 'typedoc';
import { FunctionDefinition, ObjectDefinition, UnionTypeDefinition } from './interfaces';
import schema from '../schema';
import { UnionType } from 'typedoc/dist/lib/models';
import { StringLiteralType, UnionType } from 'typedoc/dist/lib/models';

function buildObjectDefinition(obj: DeclarationReflection): ObjectDefinition {
return {
Expand Down Expand Up @@ -47,6 +47,26 @@ function buildUnionTypeDefinition(obj: DeclarationReflection, type: UnionType):
};
}

// Treat string literal type as a union with a single element.
function buildStringLiteralTypeDefinition(obj: DeclarationReflection, type: StringLiteralType): UnionTypeDefinition {
return {
name: schema.code.buildFullName(obj),
type: 'union',
values: [
(() => {
const result = schema.code.buildType(type);
try {
return JSON.parse(result);
} catch (e) {
// ignore json parse errors
}
/* istanbul ignore next */
return result;
})(),
],
};
}

export default function buildTypeDefinition(
obj: DeclarationReflection
): ObjectDefinition | FunctionDefinition | UnionTypeDefinition {
Expand All @@ -61,6 +81,10 @@ export default function buildTypeDefinition(
definition = buildUnionTypeDefinition(obj, obj.type);
}

if (schema.types.isStringLiteralType(obj.type)) {
definition = buildStringLiteralTypeDefinition(obj, obj.type);
}

if (obj.signatures) {
definition = buildFunctionDefinition(obj.parent!, obj.signatures[0]);
}
Expand Down
27 changes: 25 additions & 2 deletions test/components/complex-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import { ComponentDefinition } from '../../src/components/interfaces';
import { buildProject } from './test-helpers';

let buttonGroup: ComponentDefinition;
let sideNavigation: ComponentDefinition;
let table: ComponentDefinition;

beforeAll(() => {
const result = buildProject('complex-types');
expect(result).toHaveLength(2);
expect(result).toHaveLength(3);

[sideNavigation, table] = result;
[buttonGroup, sideNavigation, table] = result;
});

test('should only have expected properties, regions and events', () => {
Expand Down Expand Up @@ -139,3 +140,25 @@ test('should properly display string union types', () => {
],
});
});

test('should parse string literal type as single-value union', () => {
expect(buttonGroup.properties).toEqual([
{
name: 'items',
description: 'This is items array',
type: 'ReadonlyArray<ButtonGroupProps.Item>',
optional: false,
},
{
name: 'variant',
description: 'This is variant',
type: 'string',
inlineType: {
name: 'ButtonGroupProps.Variant',
type: 'union',
values: ['icon'],
},
optional: false,
},
]);
});

0 comments on commit 72b4157

Please sign in to comment.