Skip to content

Commit

Permalink
[core] Rework typescript-to-proptypes
Browse files Browse the repository at this point in the history
  • Loading branch information
flaviendelangle committed Aug 16, 2023
1 parent 2ac3eaa commit 5c0357b
Show file tree
Hide file tree
Showing 11 changed files with 2,029 additions and 220 deletions.
319 changes: 191 additions & 128 deletions packages/api-docs-builder/utils/getPropsFromComponentSymbol.ts

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions packages/api-docs-builder/utils/parseStyles.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as ts from 'typescript';
import { getSymbolDescription } from '../buildApiUtils';
import { TypeScriptProject } from './createTypeScriptProject';
import getPropsFromComponentSymbol from './getPropsFromComponentSymbol';
import { getPropsFromComponentSymbol } from './getPropsFromComponentSymbol';
import resolveExportSpecifier from './resolveExportSpecifier';

export interface Classes {
classes: string[];
Expand Down Expand Up @@ -78,10 +79,14 @@ export default function parseStyles({
throw new Error(`No exported component for the componentName "${componentName}"`);
}

const localeSymbol = resolveExportSpecifier(exportedSymbol, project);
const declaration = localeSymbol.valueDeclaration!;

const classesProp = getPropsFromComponentSymbol({
symbol: exportedSymbol,
node: declaration,
project,
shouldInclude: ({ name }) => name === 'classes',
checkDeclarations: true,
})?.classes;
if (classesProp == null) {
// We could not infer the type of the classes prop, so we try to extract them from the {ComponentName}Classes interface
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Badge/Badge.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ Badge.propTypes /* remove-proptypes */ = {
* The component used for the root node.
* Either a string to use a HTML element or a component.
*/
component: PropTypes.elementType,
component: PropTypes.elementType.isRequired,
/**
* The components used for each slot inside.
*
Expand Down
4 changes: 4 additions & 0 deletions packages/typescript-to-proptypes/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ export * from './parser';
export * from './injector';
export * from './types';
export { ts };

export { getPropTypesFromFile } from './v2/getPropTypesFromFile';
export { injectPropTypesInFile } from './v2/injectPropTypesInFile';
export type { InjectPropTypesInFileOptions } from './v2/injectPropTypesInFile';
16 changes: 0 additions & 16 deletions packages/typescript-to-proptypes/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -737,19 +737,3 @@ export function parseFromProgram(

return programNode;
}

/**
* Creates a program, parses the specified file and returns the PropTypes as an AST, if you need to parse more than one file
* use `createProgram` and `parseFromProgram` for better performance
* @param filePath The file to parse
* @param options The options from `loadConfig`
* @param parserOptions Options that specify how the parser should act
*/
export function parseFile(
filePath: string,
options: ts.CompilerOptions,
parserOptions: Partial<ParserOptions> = {},
) {
const program = ts.createProgram([filePath], options);
return parseFromProgram(filePath, program, parserOptions);
}
180 changes: 180 additions & 0 deletions packages/typescript-to-proptypes/src/v2/createType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import _ from 'lodash';
import {
PropType,
ArrayType,
LiteralType,
BooleanType,
AnyType,
UnionType,
BasePropType,
ElementType,
DOMElementType,
InstanceOfType,
InterfaceType,
FunctionType,
StringType,
ObjectType,
NumericType,
} from './models';

export function createAnyType(init: { jsDoc: string | undefined }): AnyType {
return {
type: 'any',
jsDoc: init.jsDoc,
};
}

export function createArrayType(init: {
arrayType: PropType;
jsDoc: string | undefined;
}): ArrayType {
return {
type: 'array',
jsDoc: init.jsDoc,
arrayType: init.arrayType,
};
}

export function createBooleanType(init: { jsDoc: string | undefined }): BooleanType {
return {
type: 'boolean',
jsDoc: init.jsDoc,
};
}

export function createDOMElementType(init: {
optional: boolean | undefined;
jsDoc: string | undefined;
}): DOMElementType {
return {
type: 'DOMElementNode',
jsDoc: init.jsDoc,
optional: init.optional,
};
}

export function createElementType(init: {
elementType: ElementType['elementType'];
jsDoc: string | undefined;
}): ElementType {
return {
type: 'ElementNode',
jsDoc: init.jsDoc,
elementType: init.elementType,
};
}

export function createFunctionType(init: { jsDoc: string | undefined }): FunctionType {
return {
type: 'FunctionNode',
jsDoc: init.jsDoc,
};
}

export function createInstanceOfType(init: {
jsDoc: string | undefined;
instance: string;
}): InstanceOfType {
return {
type: 'InstanceOfNode',
instance: init.instance,
jsDoc: init.jsDoc,
};
}

export function createInterfaceType(init: {
jsDoc: string | undefined;
types: ReadonlyArray<[string, PropType]> | undefined;
}): InterfaceType {
return {
type: 'InterfaceNode',
jsDoc: init.jsDoc,
types: init.types ?? [],
};
}

export function createLiteralType(init: {
value: unknown;
jsDoc: string | undefined;
}): LiteralType {
return {
type: 'LiteralNode',
value: init.value,
jsDoc: init.jsDoc,
};
}

export function createNumericType(init: { jsDoc: string | undefined }): NumericType {
return {
type: 'NumericNode',
jsDoc: init.jsDoc,
};
}

export function createObjectType(init: { jsDoc: string | undefined }): ObjectType {
return {
type: 'ObjectNode',
jsDoc: init.jsDoc,
};
}

export function createStringType(init: { jsDoc: string | undefined }): StringType {
return {
type: 'StringNode',
jsDoc: init.jsDoc,
};
}

export interface UndefinedType extends BasePropType {
type: 'UndefinedNode';
}

export function createUndefinedType(init: { jsDoc: string | undefined }): UndefinedType {
return {
type: 'UndefinedNode',
jsDoc: init.jsDoc,
};
}

export function uniqueUnionTypes(node: UnionType): UnionType {
return {
type: node.type,
jsDoc: node.jsDoc,
types: _.uniqBy(node.types, (type) => {
if (type.type === 'LiteralNode') {
return type.value;
}

if (type.type === 'InstanceOfNode') {
return `${type.type}.${type.instance}`;
}

return type.type;
}),
};
}

export function createUnionType(init: {
jsDoc: string | undefined;
types: readonly PropType[];
}): UnionType {
const flatTypes: PropType[] = [];

function flattenTypes(nodes: readonly PropType[]) {
nodes.forEach((type) => {
if (type.type === 'UnionNode') {
flattenTypes(type.types);
} else {
flatTypes.push(type);
}
});
}

flattenTypes(init.types);

return uniqueUnionTypes({
type: 'UnionNode',
jsDoc: init.jsDoc,
types: flatTypes,
});
}
Loading

0 comments on commit 5c0357b

Please sign in to comment.