UNPKG

babel-plugin-typescript-to-proptypes

Version:
372 lines (269 loc) 15.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const core = require('@babel/core'); const types = require('@babel/types'); const extractEnumValues = require('./extractEnumValues.js'); const getTypeName = require('./getTypeName.js'); const propTypes = require('./propTypes.js'); /* eslint-disable @typescript-eslint/no-use-before-define */ const NATIVE_BUILT_INS = ['Date', 'Error', 'RegExp', 'Map', 'WeakMap', 'Set', 'WeakSet', 'Promise']; const PROP_TYPES_15_7 = 15.7; // eslint-disable-next-line complexity function convert(type, state, depth) { if (!type) { return null; } const reactImportedName = state.reactImportedName, propTypes$1 = state.propTypes; const propTypesImportedName = propTypes$1.defaultImport; const isMaxDepth = depth >= state.options.maxDepth; // Remove wrapping parens if (core.types.isTSParenthesizedType(type)) { type = type.typeAnnotation; } state.propTypes.count += 1; // any -> PropTypes.any // unknown -> PropTypes.any if (core.types.isTSAnyKeyword(type) || core.types.isTSVoidKeyword(type) || core.types.isTSUnknownKeyword(type)) { return propTypes.createMember(core.types.identifier('any'), propTypesImportedName); } // string -> PropTypes.string if (core.types.isTSStringKeyword(type)) { return propTypes.createMember(core.types.identifier('string'), propTypesImportedName); } // number -> PropTypes.number if (core.types.isTSNumberKeyword(type)) { return propTypes.createMember(core.types.identifier('number'), propTypesImportedName); } // boolean -> PropTypes.bool if (core.types.isTSBooleanKeyword(type)) { return propTypes.createMember(core.types.identifier('bool'), propTypesImportedName); } // symbol -> PropTypes.symbol if (core.types.isTSSymbolKeyword(type)) { return propTypes.createMember(core.types.identifier('symbol'), propTypesImportedName); } // object -> PropTypes.object if (core.types.isTSObjectKeyword(type)) { return propTypes.createMember(core.types.identifier('object'), propTypesImportedName); } // null -> PropTypes.oneOf([null]) if (core.types.isTSNullKeyword(type)) { return propTypes.createCall(core.types.identifier('oneOf'), [core.types.arrayExpression([core.types.nullLiteral()])], propTypesImportedName); } // 'foo' -> PropTypes.oneOf(['foo']) if (core.types.isTSLiteralType(type)) { return propTypes.createCall(core.types.identifier('oneOf'), [core.types.arrayExpression([type.literal])], propTypesImportedName); } // enum Foo {} -> PropTypes.oneOf if (core.types.isTSEnumDeclaration(type)) { return propTypes.createCall(core.types.identifier('oneOf'), [core.types.arrayExpression(extractEnumValues.extractEnumValues(type).map(value => { if (typeof value === 'number') { return core.types.numericLiteral(value); } return core.types.stringLiteral(value); }))], propTypesImportedName); } // Foo.VALUE -> * if (core.types.isTSEnumMember(type)) { if (type.initializer) { return type.initializer; } // (() => void) -> PropTypes.func } else if (core.types.isTSFunctionType(type)) { return propTypes.createMember(core.types.identifier('func'), propTypesImportedName); // React.ReactNode -> PropTypes.node // React.ReactElement -> PropTypes.element // React.MouseEvent -> PropTypes.object // React.MouseEventHandler -> PropTypes.func // React.Ref -> PropTypes.oneOfType() // JSX.Element -> PropTypes.element // FooShape, FooPropType -> FooShape, FooPropType // Date, Error, RegExp -> Date, Error, RegExp // CustomType -> PropTypes.any } else if (core.types.isTSTypeReference(type)) { const name = getTypeName.getTypeName(type.typeName); // Array<*> if (name === 'Array') { var _type$typeParameters; const val = (_type$typeParameters = type.typeParameters) === null || _type$typeParameters === void 0 ? void 0 : _type$typeParameters.params[0]; const args = convertArray(val ? [val] : [], state, depth); if (args.length === 0) { return null; } return propTypes.createCall(core.types.identifier('arrayOf'), args, propTypesImportedName); } // Record<string, string> -> PropTypes.objectOf(PropTypes.string) if (name === 'Record') { var _type$typeParameters2; const result = convert((_type$typeParameters2 = type.typeParameters) === null || _type$typeParameters2 === void 0 ? void 0 : _type$typeParameters2.params[1], state, depth); return result ? propTypes.createCall(core.types.identifier('objectOf'), [result], propTypesImportedName) : null; } // node if (propTypes.isReactTypeMatch(name, 'ReactText', reactImportedName) || propTypes.isReactTypeMatch(name, 'ReactNode', reactImportedName) || propTypes.isReactTypeMatch(name, 'ReactType', reactImportedName) || propTypes.isReactTypeMatch(name, 'ElementType', reactImportedName)) { return propTypes.createMember(core.types.identifier('node'), propTypesImportedName); } // function if (propTypes.isReactTypeMatch(name, 'ComponentType', reactImportedName) || propTypes.isReactTypeMatch(name, 'ComponentClass', reactImportedName) || propTypes.isReactTypeMatch(name, 'StatelessComponent', reactImportedName) || propTypes.isReactTypeMatch(name, 'ElementType', reactImportedName)) { return propTypes.getInstalledPropTypesVersion() >= PROP_TYPES_15_7 ? propTypes.createMember(core.types.identifier('elementType'), propTypesImportedName) : propTypes.createMember(core.types.identifier('func'), propTypesImportedName); } // element if (propTypes.isReactTypeMatch(name, 'Element', 'JSX') || propTypes.isReactTypeMatch(name, 'ReactElement', reactImportedName) || propTypes.isReactTypeMatch(name, 'ComponentElement', reactImportedName) || propTypes.isReactTypeMatch(name, 'FunctionComponentElement', reactImportedName) || propTypes.isReactTypeMatch(name, 'DOMElement', reactImportedName) || propTypes.isReactTypeMatch(name, 'SFCElement', reactImportedName)) { return propTypes.createMember(core.types.identifier('element'), propTypesImportedName); } // oneOfType if (propTypes.isReactTypeMatch(name, 'Ref', reactImportedName)) { return propTypes.createCall(core.types.identifier('oneOfType'), [core.types.arrayExpression([propTypes.createMember(core.types.identifier('string'), propTypesImportedName), propTypes.createMember(core.types.identifier('func'), propTypesImportedName), propTypes.createMember(core.types.identifier('object'), propTypesImportedName)])], propTypesImportedName); } // function if (name.endsWith('Handler')) { return propTypes.createMember(core.types.identifier('func'), propTypesImportedName); } // object if (name.endsWith('Event')) { return propTypes.createMember(core.types.identifier('object'), propTypesImportedName); } // native built-ins if (NATIVE_BUILT_INS.includes(name)) { return propTypes.createCall(core.types.identifier('instanceOf'), [core.types.identifier(name)], propTypesImportedName); } // inline references if (state.referenceTypes[name]) { return convert(state.referenceTypes[name], state, depth); } // custom prop type variables if (propTypes.hasCustomPropTypeSuffix(name, state.options.customPropTypeSuffixes)) { return core.types.identifier(name); } // Nothing found. If explicitly requested, return a prop type with "any", // otherwise omit the prop. return state.options.mapUnknownReferenceTypesToAny ? propTypes.createMember(core.types.identifier('any'), propTypesImportedName) : null; // [] -> PropTypes.arrayOf(), PropTypes.array } else if (core.types.isTSArrayType(type)) { const args = convertArray([type.elementType], state, depth); return args.length > 0 ? propTypes.createCall(core.types.identifier('arrayOf'), args, propTypesImportedName) : propTypes.createMember(core.types.identifier('array'), propTypesImportedName); // {} -> PropTypes.object // { [key: string]: string } -> PropTypes.objectOf(PropTypes.string) // { foo: string } -> PropTypes.shape({ foo: PropTypes.string }) } else if (core.types.isTSTypeLiteral(type)) { // object if (type.members.length === 0 || isMaxDepth) { return propTypes.createMember(core.types.identifier('object'), propTypesImportedName); } // func if (type.members.some(member => core.types.isTSCallSignatureDeclaration(member))) { return propTypes.createMember(core.types.identifier('func'), propTypesImportedName); } // objectOf if (type.members.length === 1 && core.types.isTSIndexSignature(type.members[0])) { var _index$typeAnnotation; const index = type.members[0]; if ((_index$typeAnnotation = index.typeAnnotation) !== null && _index$typeAnnotation !== void 0 && _index$typeAnnotation.typeAnnotation) { const result = convert(index.typeAnnotation.typeAnnotation, state, depth); if (result) { return propTypes.createCall(core.types.identifier('objectOf'), [result], propTypesImportedName); } } // shape } else { return propTypes.createCall(core.types.identifier('shape'), [core.types.objectExpression(convertListToProps(type.members.filter(member => core.types.isTSPropertySignature(member)), state, [], depth + 1))], propTypesImportedName); } // { [K in Type]: string } -> PropTypes.objectOf(PropTypes.string) } else if (core.types.isTSMappedType(type)) { const result = convert(type.typeAnnotation, state, depth); if (result) { return propTypes.createCall(core.types.identifier('objectOf'), [result], propTypesImportedName); } // string | number -> PropTypes.oneOfType([PropTypes.string, PropTypes.number]) // 'foo' | 'bar' -> PropTypes.oneOf(['foo', 'bar']) } else if (core.types.isTSUnionType(type) || core.types.isTSIntersectionType(type)) { const isAllLiterals = type.types.every(param => core.types.isTSLiteralType(param)); const containsAny = type.types.some(param => core.types.isTSAnyKeyword(param)); let label; let args; if (isAllLiterals) { args = type.types.map(param => param.literal); label = core.types.identifier('oneOf'); if (state.options.maxSize) { args = args.slice(0, state.options.maxSize); } } else if (containsAny) { return propTypes.createMember(core.types.identifier('any'), propTypesImportedName); } else { args = convertArray(type.types, state, depth); label = core.types.identifier('oneOfType'); // Contained unresolved references, so just omit for now if (args.length !== type.types.length) { return null; } } if (label && args.length > 0) { return propTypes.createCall(label, [core.types.arrayExpression(args)], propTypesImportedName); } // interface Foo {} } else if (core.types.isTSInterfaceDeclaration(type)) { // object if (type.body.body.length === 0 || isMaxDepth) { return propTypes.createMember(core.types.identifier('object'), propTypesImportedName); } // func if (type.body.body.some(member => core.types.isTSCallSignatureDeclaration(member))) { return propTypes.createMember(core.types.identifier('func'), propTypesImportedName); } // shape return propTypes.createCall(core.types.identifier('shape'), [core.types.objectExpression(convertListToProps(type.body.body.filter(property => core.types.isTSPropertySignature(property)), state, [], depth + 1))], propTypesImportedName); // type Foo = {}; } else if (core.types.isTSTypeAliasDeclaration(type)) { return convert(type.typeAnnotation, state, depth); // Type['prop'] } else if (core.types.isTSIndexedAccessType(type)) { const _type = type, objectType = _type.objectType, indexType = _type.indexType; if (core.types.isTSTypeReference(objectType) && core.types.isTSLiteralType(indexType)) { const ref = state.referenceTypes[objectType.typeName.name]; let properties; if (core.types.isTSInterfaceDeclaration(ref)) { properties = ref.body.body; } else if (core.types.isTSTypeAliasDeclaration(ref) && core.types.isTSTypeLiteral(ref.typeAnnotation)) { properties = ref.typeAnnotation.members; } else { return null; } const property = properties.find(prop => core.types.isTSPropertySignature(prop) && prop.key.name === indexType.literal.value); return property ? convert(property.typeAnnotation.typeAnnotation, state, depth) : null; } // typeof foo } else if (core.types.isTSTypeQuery(type)) { return propTypes.createMember(core.types.identifier('any'), propTypesImportedName); // keyof foo } else if (core.types.isTSTypeOperator(type) && type.operator === 'keyof') { return propTypes.createMember(core.types.identifier('any'), propTypesImportedName); } state.propTypes.count -= 1; return null; } function mustBeOptional(type) { // Unions that contain undefined or null cannot be required by design if (core.types.isTSUnionType(type)) { return type.types.some(value => core.types.isTSAnyKeyword(value) || core.types.isTSNullKeyword(value) || core.types.isTSUndefinedKeyword(value)); } return false; } function convertArray(types, state, depth) { const propTypes = []; types.forEach(type => { const prop = convert(type, state, depth); if (prop) { propTypes.push(prop); } }); return propTypes; } function convertListToProps(properties, state, defaultProps, depth) { const propTypes$1 = []; let hasChildren = false; let size = 0; properties.some(property => { if (state.options.maxSize && size === state.options.maxSize) { return true; } if (!property.typeAnnotation) { return false; } const type = property.typeAnnotation.typeAnnotation; const propType = convert(type, state, depth); const name = property.key.name; if (propType) { const objProperty = core.types.objectProperty(property.key, propTypes.wrapIsRequired(propType, !state.options.strict || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing property.optional || defaultProps.includes(name) || mustBeOptional(type))); if (state.options.comments && property.leadingComments) { property.leadingComments.forEach(comment => { types.addComment(objProperty, 'leading', comment.value); }); } propTypes$1.push(objProperty); if (name === 'children') { hasChildren = true; } size += 1; } return false; }); // Only append implicit children when the root list is being created if (!hasChildren && depth === 0 && propTypes$1.length > 0 && state.options.implicitChildren) { propTypes$1.push(core.types.objectProperty(core.types.identifier('children'), propTypes.createMember(core.types.identifier('node'), state.propTypes.defaultImport))); } return propTypes$1; } function convertToPropTypes(types, typeNames, state, defaultProps) { const properties = []; typeNames.forEach(typeName => { if (types[typeName]) { properties.push(...convertListToProps(types[typeName], state, defaultProps, 0)); } }); return properties; } exports.convertToPropTypes = convertToPropTypes; //# sourceMappingURL=convertBabelToPropTypes.js.map