Skip to content

Commit

Permalink
support exactOptionalPropertyTypes
Browse files Browse the repository at this point in the history
resolves #23
  • Loading branch information
quisido committed Jul 12, 2023
1 parent ec7fac7 commit 38aa6ff
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 11 deletions.
23 changes: 23 additions & 0 deletions fixtures/components/exact-optional-property-types/button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
import { CancelableEventHandler } from '../../internal/events';

export interface ButtonProps {
/**
* String example
*/
children: string;

/**
* Fired when user clicks
*/
onClick?: CancelableEventHandler | undefined;
}

/**
* Component-level description
*/
export default function Button({ children, onClick }: ButtonProps) {
return <button onClick={onClick}>{children}</button>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.json",
"include": ["./**/*.tsx"]
}
49 changes: 38 additions & 11 deletions src/components/build-definition.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,58 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { DeclarationReflection, ReflectionKind } from 'typedoc';
import { Type } from 'typedoc/dist/lib/models';
import { ReferenceType, Type } from 'typedoc/dist/lib/models';
import { ComponentDefinition, ComponentFunction } from './interfaces';
import schema from '../schema';
import buildTypeDefinition from './build-type-definition';
import extractDefaultValues from './default-values-extractor';

function mapHandlerToEventInfo(handler: DeclarationReflection) {
return {
name: handler.name,
description: schema.code.buildNodeDescription(handler),
deprecatedTag: handler.comment?.tags?.find(tag => tag.tagName === 'deprecated')?.text.trim(),
};
}

function mapReferenceToEventInfo(reference: ReferenceType) {
const cancelable = reference.name !== 'NonCancelableEventHandler';
const detailType = reference.typeArguments?.[0];
if (typeof detailType === 'undefined') {
return {
cancelable,
detailInlineType: undefined,
detailType: undefined,
};
}
const { typeName, typeDefinition } = getPropertyType(detailType);
return {
cancelable,
detailInlineType: typeDefinition,
detailType: typeName,
};
}

function buildEventInfo(handler: DeclarationReflection) {
if (schema.utils.isOptionalDeclaration(handler) && schema.types.isUnionType(handler.type)) {
const reference = handler.type.types.find(schema.types.isReferenceType);
if (typeof reference !== 'undefined') {
return {
...mapHandlerToEventInfo(handler),
...mapReferenceToEventInfo(reference),
};
}
}
if (!schema.types.isReferenceType(handler.type)) {
throw new Error(
`Unknown event handler type: ${handler.type && handler.type.type} at ${schema.utils.getDeclarationSourceFilename(
handler
)}`
);
}
const detailType = handler.type.typeArguments?.[0];
const { typeName, typeDefinition } = detailType
? getPropertyType(detailType)
: { typeName: undefined, typeDefinition: undefined };
return {
name: handler.name,
description: schema.code.buildNodeDescription(handler),
cancelable: handler.type.name !== 'NonCancelableEventHandler',
detailType: typeName,
detailInlineType: typeDefinition,
deprecatedTag: handler.comment?.tags?.find(tag => tag.tagName === 'deprecated')?.text.trim(),
...mapHandlerToEventInfo(handler),
...mapReferenceToEventInfo(handler.type),
};
}

Expand Down
35 changes: 35 additions & 0 deletions test/components/exact-optional-properties-types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { ComponentDefinition } from '../../src/components/interfaces';
import { buildProject } from './test-helpers';

let component: ComponentDefinition;
beforeAll(() => {
const result = buildProject('exact-optional-property-types');
expect(result).toHaveLength(1);

component = result[0];
});

test('should have correct properties', () => {
expect(component.properties).toEqual([
{
name: 'children',
description: 'String example',
type: 'string',
optional: false,
defaultValue: undefined,
},
]);
});

test('should have correct events', () => {
expect(component.events).toEqual([
{
name: 'onClick',
description: 'Fired when user clicks',
cancelable: true,
detailType: undefined,
},
]);
});

0 comments on commit 38aa6ff

Please sign in to comment.