@atlaskit/forge-react-types 0.42.8 → 0.42.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/types/components/__generated__/BadgeProps.codegen.d.ts +2 -7
- package/dist/types/components/__generated__/BoxProps.codegen.d.ts +2 -2
- package/dist/types/components/__generated__/CalendarProps.codegen.d.ts +128 -4
- package/dist/types/components/__generated__/CodeProps.codegen.d.ts +2 -2
- package/dist/types/components/__generated__/HeadingProps.codegen.d.ts +29 -3
- package/dist/types/components/__generated__/PressableProps.codegen.d.ts +2 -2
- package/dist/types/components/__generated__/RangeProps.codegen.d.ts +50 -5
- package/dist/types/components/__generated__/index.d.ts +0 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types-ts4.5/components/__generated__/BadgeProps.codegen.d.ts +2 -7
- package/dist/types-ts4.5/components/__generated__/BoxProps.codegen.d.ts +2 -2
- package/dist/types-ts4.5/components/__generated__/CalendarProps.codegen.d.ts +128 -4
- package/dist/types-ts4.5/components/__generated__/CodeProps.codegen.d.ts +2 -2
- package/dist/types-ts4.5/components/__generated__/HeadingProps.codegen.d.ts +29 -3
- package/dist/types-ts4.5/components/__generated__/PressableProps.codegen.d.ts +2 -2
- package/dist/types-ts4.5/components/__generated__/RangeProps.codegen.d.ts +50 -5
- package/dist/types-ts4.5/components/__generated__/index.d.ts +0 -1
- package/dist/types-ts4.5/index.d.ts +1 -1
- package/package.json +1 -4
- package/scripts/codegen/codeGenerator.ts +114 -24
- package/scripts/codegen/typeSerializer.ts +122 -70
- package/scripts/codegen/utils.ts +71 -0
- package/scripts/typechecker.ts +17 -2
- package/src/components/__generated__/BadgeProps.codegen.tsx +3 -7
- package/src/components/__generated__/CalendarProps.codegen.tsx +119 -4
- package/src/components/__generated__/CodeProps.codegen.tsx +2 -2
- package/src/components/__generated__/HeadingProps.codegen.tsx +31 -3
- package/src/components/__generated__/RangeProps.codegen.tsx +54 -5
- package/src/components/__generated__/index.ts +1 -2
- package/src/index.ts +0 -2
- package/dist/cjs/components/__generated__/BleedProps.codegen.js +0 -5
- package/dist/es2019/components/__generated__/BleedProps.codegen.js +0 -1
- package/dist/esm/components/__generated__/BleedProps.codegen.js +0 -1
- package/dist/types/components/__generated__/BleedProps.codegen.d.ts +0 -15
- package/dist/types-ts4.5/components/__generated__/BleedProps.codegen.d.ts +0 -15
- package/src/components/__generated__/BleedProps.codegen.tsx +0 -22
|
@@ -3,14 +3,59 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Extract component prop types from UIKit 2 components - RangeProps
|
|
5
5
|
*
|
|
6
|
-
* @codegen <<SignedSource::
|
|
6
|
+
* @codegen <<SignedSource::630c202e2564f5bfeac2d313285aad09>>
|
|
7
7
|
* @codegenCommand yarn workspace @atlaskit/forge-react-types codegen
|
|
8
|
-
* @codegenDependency ../../../../forge-ui/src/components/UIKit/range/__generated__/index.partial.tsx <<SignedSource::
|
|
8
|
+
* @codegenDependency ../../../../forge-ui/src/components/UIKit/range/__generated__/index.partial.tsx <<SignedSource::d9ea91886a193f2c5119bc1ed1b50c71>>
|
|
9
9
|
*/
|
|
10
|
-
import React from 'react';
|
|
11
|
-
import PlatformRange from '@atlaskit/range';
|
|
12
10
|
import type { EventHandlerProps } from './types.codegen';
|
|
13
|
-
type PlatformRangeProps =
|
|
11
|
+
type PlatformRangeProps = {
|
|
12
|
+
/**
|
|
13
|
+
* Sets the maximum value of the range.
|
|
14
|
+
*/
|
|
15
|
+
max?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Sets the minimum value of the range.
|
|
18
|
+
*/
|
|
19
|
+
min?: number;
|
|
20
|
+
name?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Sets the step value for the range.
|
|
23
|
+
*/
|
|
24
|
+
step?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Sets the value of the range.
|
|
27
|
+
*/
|
|
28
|
+
value?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Hook to be invoked on change of the range.
|
|
31
|
+
*/
|
|
32
|
+
onChange?: (value: number) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Sets the default value if range is not set.
|
|
35
|
+
*/
|
|
36
|
+
defaultValue?: number;
|
|
37
|
+
id?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Indicates the entered value does not conform to the format expected by the application.
|
|
40
|
+
* @see aria-errormessage.
|
|
41
|
+
*/
|
|
42
|
+
"aria-invalid"?: false | true | 'false' | 'true' | 'grammar' | 'spelling';
|
|
43
|
+
/**
|
|
44
|
+
* Identifies the element (or elements) that labels the current element.
|
|
45
|
+
* @see aria-describedby.
|
|
46
|
+
*/
|
|
47
|
+
"aria-labelledby"?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Sets whether the field range is disabled.
|
|
50
|
+
*/
|
|
51
|
+
isDisabled?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* A `testId` prop is provided for specific elements. This is a unique string
|
|
54
|
+
* that appears as a data attribute `data-testid` in the rendered code and
|
|
55
|
+
* serves as a hook for automated tests.
|
|
56
|
+
*/
|
|
57
|
+
testId?: string;
|
|
58
|
+
};
|
|
14
59
|
export type RangeProps = Pick<PlatformRangeProps, 'defaultValue' | 'max' | 'min' | 'step' | 'testId' | 'onChange' | 'id' | 'isDisabled' | 'value' | 'aria-invalid' | 'aria-labelledby' | 'name'> & Pick<EventHandlerProps, 'onBlur' | 'onFocus'>;
|
|
15
60
|
/**
|
|
16
61
|
* A range lets users choose an approximate value on a slider.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export type { BadgeProps, TBadge } from './BadgeProps.codegen';
|
|
2
|
-
export type { BleedProps, TBleed } from './BleedProps.codegen';
|
|
3
2
|
export type { BoxProps, TBox } from './BoxProps.codegen';
|
|
4
3
|
export type { ButtonGroupProps, TButtonGroup } from './ButtonGroupProps.codegen';
|
|
5
4
|
export type { ButtonProps, TButton } from './ButtonProps.codegen';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { AdfRendererProps, BadgeProps,
|
|
1
|
+
export type { AdfRendererProps, BadgeProps, BoxProps, ButtonGroupProps, ButtonProps, CalendarProps, CheckboxProps, CheckboxGroupProps, CodeBlockProps, CodeProps, CommentProps, DatePickerProps, DynamicTableProps, EmptyStateProps, ErrorMessageProps, FlexProps, FormFooterProps, FormHeaderProps, FormProps, FormSectionProps, GridProps, HeadingProps, HelperMessageProps, IconProps, InlineProps, LabelProps, LinkButtonProps, ListProps, ListItemProps, LoadingButtonProps, LozengeProps, ModalBodyProps, ModalFooterProps, ModalHeaderProps, ModalProps, ModalTitleProps, ModalTransitionProps, ProgressBarProps, ProgressTrackerProps, RadioGroupProps, RadioProps, RangeProps, SectionMessageActionProps, SectionMessageProps, SelectProps, SpinnerProps, StackProps, TabListProps, TabPanelProps, TabProps, TabsProps, TagGroupProps, TagProps, TextProps, TextAreaProps, TextfieldProps, ToggleProps, TooltipProps, TimePickerProps, ValidMessageProps, PopupProps, InlineEditProps, ChromelessEditorProps, CommentEditorProps, PressableProps, TBadge, TBox, TButtonGroup, TButton, TCalendar, TCheckbox, TCheckboxGroup, TCodeBlock, TCode, TComment, TDatePicker, TDynamicTable, TEmptyState, TErrorMessage, TFlex, TFormFooter, TFormHeader, TForm, TFormSection, TGrid, THeading, THelperMessage, TIcon, TInline, TInlineEdit, TLabel, TLinkButton, TList, TListItem, TLoadingButton, TLozenge, TModalBody, TModalFooter, TModalHeader, TModal, TModalTitle, TModalTransition, TProgressBar, TProgressTracker, TRadioGroup, TRadio, TRange, TSectionMessageAction, TSectionMessage, TSelect, TSpinner, TStack, TTabList, TTabPanel, TTab, TTabs, TTagGroup, TTag, TTextArea, TTextfield, TTimePicker, TToggle, TTooltip, TValidMessage, TPopup, TAdfRenderer, TText, TChromelessEditor, TCommentEditor, TPressable, } from './components/__generated__';
|
|
2
2
|
export type { BarChartProps, StackBarChartProps, HorizontalStackBarChartProps, HorizontalBarChartProps, LineChartProps, DonutChartProps, PieChartProps, TBarChart, TStackBarChart, THorizontalStackBarChart, THorizontalBarChart, TLineChart, TDonutChart, TPieChart, } from './components/charts';
|
|
3
3
|
export type { ChartColorTokens } from './types';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/forge-react-types",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.9",
|
|
4
4
|
"description": "Component types for Forge UI Kit React components",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -25,14 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@atlaskit/button": "^23.2.0",
|
|
28
|
-
"@atlaskit/calendar": "^17.1.0",
|
|
29
28
|
"@atlaskit/checkbox": "^17.1.0",
|
|
30
29
|
"@atlaskit/comment": "^13.0.0",
|
|
31
30
|
"@atlaskit/datetime-picker": "^17.0.0",
|
|
32
31
|
"@atlaskit/dynamic-table": "^18.2.0",
|
|
33
32
|
"@atlaskit/empty-state": "^10.1.0",
|
|
34
33
|
"@atlaskit/form": "^12.0.0",
|
|
35
|
-
"@atlaskit/heading": "^5.2.0",
|
|
36
34
|
"@atlaskit/inline-edit": "^15.3.0",
|
|
37
35
|
"@atlaskit/lozenge": "^13.0.0",
|
|
38
36
|
"@atlaskit/modal-dialog": "^14.2.0",
|
|
@@ -41,7 +39,6 @@
|
|
|
41
39
|
"@atlaskit/progress-bar": "^4.0.0",
|
|
42
40
|
"@atlaskit/progress-tracker": "^10.2.0",
|
|
43
41
|
"@atlaskit/radio": "^8.1.0",
|
|
44
|
-
"@atlaskit/range": "^9.1.0",
|
|
45
42
|
"@atlaskit/section-message": "^8.2.0",
|
|
46
43
|
"@atlaskit/select": "^21.1.0",
|
|
47
44
|
"@atlaskit/spinner": "^18.0.0",
|
|
@@ -5,10 +5,21 @@ import {
|
|
|
5
5
|
type SourceFile,
|
|
6
6
|
type TypeAliasDeclaration,
|
|
7
7
|
type ImportDeclaration,
|
|
8
|
+
type TypeReferenceNode,
|
|
9
|
+
SyntaxKind,
|
|
8
10
|
} from 'ts-morph';
|
|
9
11
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
10
12
|
import kebabCase from 'lodash/kebabCase';
|
|
11
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
serializeTypeReferenceWithPickType,
|
|
15
|
+
extractPickKeys,
|
|
16
|
+
extractOmitKeys,
|
|
17
|
+
} from './typeSerializer';
|
|
18
|
+
import {
|
|
19
|
+
findTypeReferenceFromUnionOrIntersect,
|
|
20
|
+
getTypeNodeFromSymbol,
|
|
21
|
+
makePickOrOmitPredicate,
|
|
22
|
+
} from './utils';
|
|
12
23
|
|
|
13
24
|
const getNames = (symbol: Symbol) => {
|
|
14
25
|
const name = symbol.getName();
|
|
@@ -224,7 +235,7 @@ class SimpleImportDeclaration implements IImportDeclaration {
|
|
|
224
235
|
.map((name) => `type ${name}`);
|
|
225
236
|
const importedNames =
|
|
226
237
|
importedNamesList.length > 0 ? `{ ${importedNamesList.join(', ')} }` : null;
|
|
227
|
-
const defaultImport = this.defaultImport ?
|
|
238
|
+
const defaultImport = this.defaultImport ? `type ${this.defaultImport}` : null;
|
|
228
239
|
return `import ${[defaultImport, importedNames].filter(Boolean).join(', ')} from '${this.packageName}';`;
|
|
229
240
|
}
|
|
230
241
|
}
|
|
@@ -567,12 +578,21 @@ const registeredExternalTypes: Record<
|
|
|
567
578
|
defaultImport: string;
|
|
568
579
|
}
|
|
569
580
|
> = {
|
|
570
|
-
'React
|
|
581
|
+
'^React\..+$': {
|
|
571
582
|
package: 'react',
|
|
572
583
|
defaultImport: 'React',
|
|
573
584
|
},
|
|
574
585
|
};
|
|
575
586
|
|
|
587
|
+
const findExternalTypeInfo = (typeName: string) => {
|
|
588
|
+
return (
|
|
589
|
+
Object.entries(registeredExternalTypes).find(
|
|
590
|
+
([externalTypePattern]) =>
|
|
591
|
+
externalTypePattern === typeName || new RegExp(externalTypePattern).test(typeName),
|
|
592
|
+
)?.[1] ?? null
|
|
593
|
+
);
|
|
594
|
+
};
|
|
595
|
+
|
|
576
596
|
// consolidate external types into import declarations
|
|
577
597
|
const consolidateImportDeclarations = (
|
|
578
598
|
importDeclarations: ImportDeclarationProxy[],
|
|
@@ -580,7 +600,7 @@ const consolidateImportDeclarations = (
|
|
|
580
600
|
): IImportDeclaration[] => {
|
|
581
601
|
const declarations: IImportDeclaration[] = [...importDeclarations];
|
|
582
602
|
externalTypes.forEach((typeName) => {
|
|
583
|
-
const typePackage =
|
|
603
|
+
const typePackage = findExternalTypeInfo(typeName);
|
|
584
604
|
if (typePackage) {
|
|
585
605
|
const existingImport = importDeclarations.find(
|
|
586
606
|
(declaration) => declaration.getBasePackage() === typePackage.package,
|
|
@@ -602,6 +622,62 @@ const consolidateImportDeclarations = (
|
|
|
602
622
|
return declarations;
|
|
603
623
|
};
|
|
604
624
|
|
|
625
|
+
const extractPlatformPropsTypeDeclarationAndTargetPropertyKeys = (
|
|
626
|
+
rawDependentTypeDeclarations: TypeAliasDeclaration[],
|
|
627
|
+
baseComponentPropsSymbol: Symbol,
|
|
628
|
+
): {
|
|
629
|
+
typeDeclaration: TypeAliasDeclaration;
|
|
630
|
+
baseComponentPropTypeReference: TypeReferenceNode;
|
|
631
|
+
omitKeys: string[];
|
|
632
|
+
pickKeys: string[];
|
|
633
|
+
} => {
|
|
634
|
+
// this pattern is used when there is special JSDoc comments override required to customize component documentation.
|
|
635
|
+
// e.g. Badge component has:
|
|
636
|
+
// PlatformBadgeProps = Omit<_PlatformBadgeProps, 'children'> & {}
|
|
637
|
+
// BadgeProps = Pick<PlatformBadgeProps, 'appearance' | 'children' | 'max' | 'testId'>
|
|
638
|
+
const specialPlatformPropsTypeDeclaration = rawDependentTypeDeclarations.find((declaration) =>
|
|
639
|
+
declaration.getName().startsWith('_Platform'),
|
|
640
|
+
);
|
|
641
|
+
const mainPlatformPropsTypeDeclaration = rawDependentTypeDeclarations.find((declaration) =>
|
|
642
|
+
declaration.getName().startsWith('Platform'),
|
|
643
|
+
);
|
|
644
|
+
if (!mainPlatformPropsTypeDeclaration && !specialPlatformPropsTypeDeclaration) {
|
|
645
|
+
throw new Error(
|
|
646
|
+
'Could not find Platform props type declaration from the component prop type source code',
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
const platformPropsTypeDeclaration =
|
|
650
|
+
specialPlatformPropsTypeDeclaration ?? mainPlatformPropsTypeDeclaration;
|
|
651
|
+
|
|
652
|
+
const typeWhichPicksPlatformProps = findTypeReferenceFromUnionOrIntersect(
|
|
653
|
+
getTypeNodeFromSymbol(baseComponentPropsSymbol!)!,
|
|
654
|
+
makePickOrOmitPredicate('Pick', 'Platform'),
|
|
655
|
+
);
|
|
656
|
+
if (!typeWhichPicksPlatformProps) {
|
|
657
|
+
throw new Error(
|
|
658
|
+
`Could not find type which picks platform props from the component prop type source code for ${baseComponentPropsSymbol.getName()}`,
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
const pickKeys = extractPickKeys(typeWhichPicksPlatformProps);
|
|
662
|
+
let omitKeys: string[] = [];
|
|
663
|
+
if (specialPlatformPropsTypeDeclaration && mainPlatformPropsTypeDeclaration) {
|
|
664
|
+
const omitNode = mainPlatformPropsTypeDeclaration
|
|
665
|
+
.getTypeNodeOrThrow()
|
|
666
|
+
.asKindOrThrow(SyntaxKind.IntersectionType)
|
|
667
|
+
.getTypeNodes()[0]
|
|
668
|
+
.asKindOrThrow(SyntaxKind.TypeReference);
|
|
669
|
+
// if there is a special platform props type declaration, we need
|
|
670
|
+
omitKeys = extractOmitKeys(omitNode);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return {
|
|
674
|
+
typeDeclaration: platformPropsTypeDeclaration!,
|
|
675
|
+
baseComponentPropTypeReference: typeWhichPicksPlatformProps,
|
|
676
|
+
pickKeys,
|
|
677
|
+
omitKeys,
|
|
678
|
+
};
|
|
679
|
+
};
|
|
680
|
+
|
|
605
681
|
/**
|
|
606
682
|
* This function implements the new code generation logic for the component prop types.
|
|
607
683
|
* Instead of referencing to the ADS component prop types, it generates the prop types
|
|
@@ -619,24 +695,20 @@ const generateComponentPropTypeSourceCodeWithSerializedType = (
|
|
|
619
695
|
// 2) from the prop type code further extract other relevant types in the source file,
|
|
620
696
|
// and separate the platform props type declaration from the rest of the dependent types.
|
|
621
697
|
// as this will be used to generate the type code.
|
|
622
|
-
const
|
|
698
|
+
const rawDependentTypeDeclarations = getDependentTypeDeclarations(
|
|
623
699
|
baseComponentPropSymbol,
|
|
624
700
|
sourceFile,
|
|
625
|
-
)
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
}
|
|
637
|
-
return agg;
|
|
638
|
-
},
|
|
639
|
-
[[] as TypeAliasDeclaration[], null as TypeAliasDeclaration | null],
|
|
701
|
+
);
|
|
702
|
+
const {
|
|
703
|
+
omitKeys,
|
|
704
|
+
typeDeclaration: platformPropsTypeDeclaration,
|
|
705
|
+
baseComponentPropTypeReference,
|
|
706
|
+
} = extractPlatformPropsTypeDeclarationAndTargetPropertyKeys(
|
|
707
|
+
rawDependentTypeDeclarations,
|
|
708
|
+
baseComponentPropSymbol,
|
|
709
|
+
);
|
|
710
|
+
const dependentTypeDeclarations = rawDependentTypeDeclarations.filter(
|
|
711
|
+
(declaration) => declaration !== platformPropsTypeDeclaration,
|
|
640
712
|
);
|
|
641
713
|
|
|
642
714
|
// 3) extract the import statement
|
|
@@ -654,9 +726,20 @@ const generateComponentPropTypeSourceCodeWithSerializedType = (
|
|
|
654
726
|
);
|
|
655
727
|
|
|
656
728
|
// 5) serialize the prop type for the @atlaskit component (e.g. PlatformButtonProps)
|
|
657
|
-
const [typeDefCode, usedExternalTypes] =
|
|
658
|
-
|
|
659
|
-
|
|
729
|
+
const [typeDefCode, usedExternalTypes] = serializeTypeReferenceWithPickType(
|
|
730
|
+
baseComponentPropTypeReference,
|
|
731
|
+
({ jsDoc, typeCode, propertySignature }) => {
|
|
732
|
+
const propertyName = propertySignature.getName();
|
|
733
|
+
if (omitKeys.includes(propertyName)) {
|
|
734
|
+
return {
|
|
735
|
+
typeCode,
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
return {
|
|
739
|
+
jsDoc,
|
|
740
|
+
typeCode,
|
|
741
|
+
};
|
|
742
|
+
},
|
|
660
743
|
);
|
|
661
744
|
|
|
662
745
|
// 6) generate the source file
|
|
@@ -739,7 +822,14 @@ const codeConsolidators: Record<string, CodeConsolidator> = {
|
|
|
739
822
|
PressableProps: handleXCSSProp,
|
|
740
823
|
};
|
|
741
824
|
|
|
742
|
-
const typeSerializableComponentPropSymbols = [
|
|
825
|
+
const typeSerializableComponentPropSymbols = [
|
|
826
|
+
'CalendarProps',
|
|
827
|
+
'CodeProps',
|
|
828
|
+
'CodeBlockProps',
|
|
829
|
+
'BadgeProps',
|
|
830
|
+
'HeadingProps',
|
|
831
|
+
'RangeProps',
|
|
832
|
+
];
|
|
743
833
|
|
|
744
834
|
const generateComponentPropTypeSourceCode = (
|
|
745
835
|
componentPropSymbol: Symbol,
|
|
@@ -1,56 +1,32 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type Symbol as TSSymbol,
|
|
3
2
|
type Node,
|
|
4
|
-
type TypeChecker,
|
|
5
3
|
type PropertySignature,
|
|
6
4
|
type Type as TSType,
|
|
5
|
+
type UnionTypeNode,
|
|
6
|
+
type TypeReferenceNode,
|
|
7
7
|
SyntaxKind,
|
|
8
8
|
} from 'ts-morph';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
type PropertyCallback = ({
|
|
11
|
+
jsDoc,
|
|
12
|
+
typeCode,
|
|
13
|
+
propertySignature,
|
|
14
|
+
}: {
|
|
15
|
+
jsDoc?: string;
|
|
16
|
+
typeCode: string;
|
|
17
|
+
propertySignature: PropertySignature;
|
|
18
|
+
}) => {
|
|
19
|
+
jsDoc?: string;
|
|
20
|
+
typeCode: string;
|
|
21
|
+
} | null;
|
|
19
22
|
|
|
23
|
+
export const serializeTypeReferenceWithPickType = (
|
|
24
|
+
typeReference: TypeReferenceNode,
|
|
25
|
+
propertyCallback: PropertyCallback,
|
|
26
|
+
): [string, Set<string>] => {
|
|
20
27
|
const usedExternalTypes = new Set<string>();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const typeNode = typeAlias.getTypeNode();
|
|
24
|
-
if (typeNode && isCommonComponentPropType(typeNode)) {
|
|
25
|
-
const serializedType = flattenPickType(
|
|
26
|
-
typeNode.asKindOrThrow(SyntaxKind.TypeReference),
|
|
27
|
-
typeChecker,
|
|
28
|
-
usedExternalTypes,
|
|
29
|
-
);
|
|
30
|
-
return [serializedType, usedExternalTypes];
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
throw new Error(
|
|
35
|
-
`Unsupported declaration kind: ${declaration.getKindName()} for symbol: ${symbol.getName()}`,
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Checks if a node is a common component prop type. e.g.
|
|
41
|
-
*
|
|
42
|
-
* export type BleedProps = Pick<
|
|
43
|
-
* PlatformBleedProps,
|
|
44
|
-
* 'children' | 'all' | 'inline' | 'block' | 'testId' | 'role'
|
|
45
|
-
* >;
|
|
46
|
-
*/
|
|
47
|
-
const isCommonComponentPropType = (node: Node) => {
|
|
48
|
-
if (node.getKind() === SyntaxKind.TypeReference) {
|
|
49
|
-
const typeRef = node.asKindOrThrow(SyntaxKind.TypeReference);
|
|
50
|
-
const typeName = typeRef.getTypeName().getText();
|
|
51
|
-
return typeName === 'Pick';
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
28
|
+
const serializedType = flattenPickType(typeReference, usedExternalTypes, propertyCallback);
|
|
29
|
+
return [serializedType, usedExternalTypes];
|
|
54
30
|
};
|
|
55
31
|
|
|
56
32
|
// resolve single level type references (e.g. SupportedLanguages))
|
|
@@ -63,6 +39,54 @@ const isSimpleTypeReferenceNode = (tsType: TSType): boolean => {
|
|
|
63
39
|
return false;
|
|
64
40
|
};
|
|
65
41
|
|
|
42
|
+
// event function type that is not a React event handler
|
|
43
|
+
const isCustomEventHandlerType = (tsType: TSType): boolean => {
|
|
44
|
+
const callSignatures = tsType.getCallSignatures();
|
|
45
|
+
// we already import React, hence we don't have to serialize it
|
|
46
|
+
if (
|
|
47
|
+
callSignatures.length > 0 &&
|
|
48
|
+
callSignatures[0].getParameters().length > 1 &&
|
|
49
|
+
!tsType.getText().startsWith('React.')
|
|
50
|
+
) {
|
|
51
|
+
const analyticsEventSymbol = callSignatures[0].getParameters()[1];
|
|
52
|
+
if (analyticsEventSymbol) {
|
|
53
|
+
const eventTypeName = analyticsEventSymbol
|
|
54
|
+
.getDeclarations()[0]
|
|
55
|
+
.asKind(SyntaxKind.Parameter)
|
|
56
|
+
?.getTypeNode()
|
|
57
|
+
?.getText();
|
|
58
|
+
return eventTypeName === 'UIAnalyticsEvent';
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const serializeSimpleEventType = (tsType: TSType): string => {
|
|
66
|
+
const propertyCode: string[] = tsType
|
|
67
|
+
.getProperties()
|
|
68
|
+
.map((prop) => {
|
|
69
|
+
const propertySignature = prop.getDeclarations()[0] as PropertySignature | undefined;
|
|
70
|
+
if (propertySignature) {
|
|
71
|
+
const typeCode = serializeSimpleTypeNode(resolveNonNullableType(propertySignature));
|
|
72
|
+
return `${prop.getName()}: ${typeCode}`;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
})
|
|
76
|
+
.filter(Boolean) as string[];
|
|
77
|
+
return `{ ${propertyCode.join(', ')} }`;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const serializeCustomEventHandlerType = (tsType: TSType): string => {
|
|
81
|
+
const callSignature = tsType.getCallSignatures()[0];
|
|
82
|
+
const eventSymbol = callSignature.getParameters()[0];
|
|
83
|
+
const parameterDeclaration = eventSymbol.getDeclarations()[0].asKindOrThrow(SyntaxKind.Parameter);
|
|
84
|
+
const eventType = parameterDeclaration.getType();
|
|
85
|
+
const analyticsEventName = callSignature.getParameters()[1]?.getName() ?? 'analyticsEvent';
|
|
86
|
+
const returnType = callSignature.getReturnType().getText();
|
|
87
|
+
return `(${eventSymbol.getName()}: ${serializeSimpleEventType(eventType)}, ${analyticsEventName}: any) => ${returnType}`;
|
|
88
|
+
};
|
|
89
|
+
|
|
66
90
|
const serializeSimpleTypeNode = (tsType: TSType): string => {
|
|
67
91
|
if (tsType.isStringLiteral()) {
|
|
68
92
|
return `'${tsType.getLiteralValue()}'`;
|
|
@@ -72,6 +96,8 @@ const serializeSimpleTypeNode = (tsType: TSType): string => {
|
|
|
72
96
|
const unionTypes = tsType.getUnionTypes();
|
|
73
97
|
const serializedTypes = unionTypes.map((t) => serializeSimpleTypeNode(t));
|
|
74
98
|
return serializedTypes.join(' | ');
|
|
99
|
+
} else if (isCustomEventHandlerType(tsType)) {
|
|
100
|
+
return serializeCustomEventHandlerType(tsType);
|
|
75
101
|
}
|
|
76
102
|
return tsType.getText();
|
|
77
103
|
};
|
|
@@ -98,25 +124,14 @@ const serializePropertySignatureCode = (propertySignature: PropertySignature) =>
|
|
|
98
124
|
|
|
99
125
|
const flattenPickType = (
|
|
100
126
|
typeRef: Node,
|
|
101
|
-
typeChecker: TypeChecker,
|
|
102
127
|
usedExternalTypesOutput: Set<string>,
|
|
128
|
+
propertyCallback: PropertyCallback,
|
|
103
129
|
): string => {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
if (typeArgs.length < 2) {
|
|
107
|
-
return typeRef.getText(); // Fallback if not a valid Pick
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const keysNode = typeArgs[1];
|
|
111
|
-
|
|
112
|
-
// Get the selected keys
|
|
113
|
-
const selectedKeys = extractUnionKeys(keysNode);
|
|
114
|
-
|
|
115
|
-
// Get the base type symbol
|
|
130
|
+
const pickKeys = extractPickKeys(typeRef.asKindOrThrow(SyntaxKind.TypeReference));
|
|
116
131
|
const properties = typeRef
|
|
117
132
|
.getType()
|
|
118
133
|
.getProperties()
|
|
119
|
-
.filter((prop) =>
|
|
134
|
+
.filter((prop) => pickKeys.includes(prop.getName()));
|
|
120
135
|
|
|
121
136
|
if (properties.length === 0) {
|
|
122
137
|
return '{}'; // If no properties match, return 'any'
|
|
@@ -128,19 +143,23 @@ const flattenPickType = (
|
|
|
128
143
|
if (!propertySignature) {
|
|
129
144
|
return null; // Skip if no declaration
|
|
130
145
|
}
|
|
131
|
-
const jsDoc =
|
|
132
|
-
|
|
146
|
+
const { jsDoc, typeCode } =
|
|
147
|
+
propertyCallback({
|
|
148
|
+
propertySignature,
|
|
149
|
+
jsDoc: propertySignature.getJsDocs()?.[0]?.getText(),
|
|
150
|
+
typeCode: serializePropertySignatureCode(propertySignature),
|
|
151
|
+
}) || {};
|
|
133
152
|
getUnresolvableTypes(propertySignature.getType()).forEach((typeName) => {
|
|
134
153
|
usedExternalTypesOutput.add(typeName);
|
|
135
154
|
});
|
|
136
|
-
return
|
|
155
|
+
return `${jsDoc ?? ''}\n\t${typeCode}`;
|
|
137
156
|
})
|
|
138
157
|
.filter(Boolean);
|
|
139
158
|
|
|
140
159
|
if (serializedProperties.length === 0) {
|
|
141
160
|
return '{}'; // If no properties are serialized, return empty object
|
|
142
161
|
}
|
|
143
|
-
return `{\n
|
|
162
|
+
return `{\n${serializedProperties.map((prop) => (!!prop?.trim() ? ` ${prop}` : '')).join('\n')}\n}`;
|
|
144
163
|
};
|
|
145
164
|
|
|
146
165
|
const getUnresolvableTypes = (tsType: TSType) => {
|
|
@@ -195,18 +214,51 @@ const isExternalType = (tsType: TSType): boolean => {
|
|
|
195
214
|
return filePath.includes('node_modules');
|
|
196
215
|
};
|
|
197
216
|
|
|
217
|
+
export const extractUnionKeysFromTypeReferenceNode = (
|
|
218
|
+
typeReferenceNode: TypeReferenceNode,
|
|
219
|
+
targetTypeName: 'Pick' | 'Omit',
|
|
220
|
+
): string[] => {
|
|
221
|
+
const typeName = typeReferenceNode.getTypeName().getText();
|
|
222
|
+
if (typeName !== targetTypeName) {
|
|
223
|
+
throw new Error(`Expected '${targetTypeName}' type, but found '${typeName}'`);
|
|
224
|
+
}
|
|
225
|
+
const typeArgs = typeReferenceNode.getTypeArguments();
|
|
226
|
+
if (typeArgs.length !== 2) {
|
|
227
|
+
throw new Error(
|
|
228
|
+
`Expected 2 type arguments for ${targetTypeName}, but found ${typeArgs.length}`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
const unionType = typeArgs[1];
|
|
232
|
+
return extractUnionKeys(unionType);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export const extractOmitKeys = (typeReferenceNode: TypeReferenceNode): string[] => {
|
|
236
|
+
return extractUnionKeysFromTypeReferenceNode(typeReferenceNode, 'Omit');
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export const extractPickKeys = (typeReferenceNode: TypeReferenceNode): string[] => {
|
|
240
|
+
return extractUnionKeysFromTypeReferenceNode(typeReferenceNode, 'Pick');
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const unwrapStringQuotes = (str: string): string => {
|
|
244
|
+
return str.replace(/['"]/g, '');
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const extractUnionKeysFromUnionType = (unionType: UnionTypeNode): string[] => {
|
|
248
|
+
return unionType.getTypeNodes().map((node) => {
|
|
249
|
+
if (node.getKind() === SyntaxKind.StringLiteral) {
|
|
250
|
+
return node.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
|
|
251
|
+
}
|
|
252
|
+
return unwrapStringQuotes(node.getText());
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
|
|
198
256
|
const extractUnionKeys = (keysNode: Node): string[] => {
|
|
199
257
|
if (keysNode.getKind() === SyntaxKind.UnionType) {
|
|
200
258
|
const unionType = keysNode.asKindOrThrow(SyntaxKind.UnionType);
|
|
201
|
-
return unionType
|
|
202
|
-
if (node.getKind() === SyntaxKind.StringLiteral) {
|
|
203
|
-
return node.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
|
|
204
|
-
}
|
|
205
|
-
return node.getText().replace(/['"]/g, '');
|
|
206
|
-
});
|
|
259
|
+
return extractUnionKeysFromUnionType(unionType);
|
|
207
260
|
} else if (keysNode.getKind() === SyntaxKind.StringLiteral) {
|
|
208
261
|
return [keysNode.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue()];
|
|
209
262
|
}
|
|
210
|
-
|
|
211
|
-
return [keysNode.getText().replace(/['"]/g, '')];
|
|
263
|
+
return [unwrapStringQuotes(keysNode.getText())];
|
|
212
264
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Symbol as TSSymbol,
|
|
3
|
+
type TypeReferenceNode,
|
|
4
|
+
type TypeNode,
|
|
5
|
+
SyntaxKind,
|
|
6
|
+
} from 'ts-morph';
|
|
7
|
+
|
|
8
|
+
export const getTypeNodeFromSymbol = (symbol: TSSymbol): TypeNode | null => {
|
|
9
|
+
const declaration = symbol.getDeclarations()[0];
|
|
10
|
+
if (!declaration) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (declaration.getKind() === SyntaxKind.TypeAliasDeclaration) {
|
|
15
|
+
return declaration.asKindOrThrow(SyntaxKind.TypeAliasDeclaration).getTypeNode() ?? null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type TypeFinderPredicate = (node: TypeNode) => boolean;
|
|
22
|
+
|
|
23
|
+
export const makePickOrOmitPredicate = (
|
|
24
|
+
targetTypeName: 'Pick' | 'Omit',
|
|
25
|
+
baseClassNamePrefix: string,
|
|
26
|
+
): TypeFinderPredicate => {
|
|
27
|
+
return (node: TypeNode) => {
|
|
28
|
+
const typeReferenceNode = node.asKind(SyntaxKind.TypeReference);
|
|
29
|
+
if (!typeReferenceNode) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const typeName = typeReferenceNode.getTypeName().getText();
|
|
33
|
+
if (typeName !== targetTypeName) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const baseNode = typeReferenceNode.getTypeArguments()[0]!;
|
|
37
|
+
return baseNode.getText().startsWith(baseClassNamePrefix);
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const findTypeReferenceFromUnionOrIntersect = (
|
|
42
|
+
node: TypeNode,
|
|
43
|
+
predicate: TypeFinderPredicate,
|
|
44
|
+
): TypeReferenceNode | null => {
|
|
45
|
+
if (predicate(node)) {
|
|
46
|
+
return node.asKindOrThrow(SyntaxKind.TypeReference);
|
|
47
|
+
}
|
|
48
|
+
if (node.getKind() === SyntaxKind.UnionType) {
|
|
49
|
+
const unionNode = node.asKindOrThrow(SyntaxKind.UnionType);
|
|
50
|
+
return (
|
|
51
|
+
(unionNode.getTypeNodes().find((n) => {
|
|
52
|
+
if (n.isKind(SyntaxKind.TypeReference)) {
|
|
53
|
+
return predicate(n.asKindOrThrow(SyntaxKind.TypeReference));
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}) as TypeReferenceNode) ?? null
|
|
57
|
+
);
|
|
58
|
+
} else if (node.getKind() === SyntaxKind.IntersectionType) {
|
|
59
|
+
const intersectionNode = node.asKindOrThrow(SyntaxKind.IntersectionType);
|
|
60
|
+
return (
|
|
61
|
+
(intersectionNode.getTypeNodes().find((n) => {
|
|
62
|
+
if (n.isKind(SyntaxKind.TypeReference)) {
|
|
63
|
+
return predicate(n.asKindOrThrow(SyntaxKind.TypeReference));
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}) as TypeReferenceNode) ?? null
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return null;
|
|
71
|
+
};
|
package/scripts/typechecker.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
2
|
import {
|
|
3
3
|
type BadgeProps,
|
|
4
|
-
type
|
|
4
|
+
type CalendarProps,
|
|
5
5
|
type CodeBlockProps,
|
|
6
|
+
type CodeProps,
|
|
7
|
+
type HeadingProps,
|
|
8
|
+
type RangeProps,
|
|
6
9
|
} from '@atlassian/forge-ui/src/components/UIKit';
|
|
7
10
|
import { type BadgeProps as GeneratedBadgeProps } from '../src/components/__generated__/BadgeProps.codegen';
|
|
8
|
-
import { type
|
|
11
|
+
import { type CalendarProps as GeneratedCalendarProps } from '../src/components/__generated__/CalendarProps.codegen';
|
|
9
12
|
import { type CodeBlockProps as GeneratedCodeBlockProps } from '../src/components/__generated__/CodeBlockProps.codegen';
|
|
13
|
+
import { type CodeProps as GeneratedCodeProps } from '../src/components/__generated__/CodeProps.codegen';
|
|
14
|
+
import { type HeadingProps as GeneratedHeadingProps } from '../src/components/__generated__/HeadingProps.codegen';
|
|
15
|
+
import { type RangeProps as GeneratedRangeProps } from '../src/components/__generated__/RangeProps.codegen';
|
|
10
16
|
|
|
11
17
|
const assertAssignable = <A, B extends A>() => {};
|
|
12
18
|
|
|
@@ -18,3 +24,12 @@ assertAssignable<CodeProps, GeneratedCodeProps>();
|
|
|
18
24
|
|
|
19
25
|
assertAssignable<GeneratedCodeBlockProps, CodeBlockProps>();
|
|
20
26
|
assertAssignable<CodeBlockProps, GeneratedCodeBlockProps>();
|
|
27
|
+
|
|
28
|
+
assertAssignable<GeneratedHeadingProps, HeadingProps>();
|
|
29
|
+
assertAssignable<HeadingProps, GeneratedHeadingProps>();
|
|
30
|
+
|
|
31
|
+
assertAssignable<GeneratedRangeProps, RangeProps>();
|
|
32
|
+
assertAssignable<RangeProps, GeneratedRangeProps>();
|
|
33
|
+
|
|
34
|
+
assertAssignable<GeneratedCalendarProps, CalendarProps>();
|
|
35
|
+
assertAssignable<CalendarProps, GeneratedCalendarProps>();
|