react-carousel-query
Version:
A infinite carousel component made with react that handles the pagination for you.
349 lines (295 loc) • 10.9 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getFlowType;
var _astTypes = require("ast-types");
var _getPropertyName = _interopRequireDefault(require("./getPropertyName"));
var _printValue = _interopRequireDefault(require("./printValue"));
var _getTypeAnnotation = _interopRequireDefault(require("../utils/getTypeAnnotation"));
var _resolveToValue = _interopRequireDefault(require("../utils/resolveToValue"));
var _resolveObjectKeysToArray = require("../utils/resolveObjectKeysToArray");
var _getTypeParameters = _interopRequireDefault(require("../utils/getTypeParameters"));
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/
const flowTypes = {
AnyTypeAnnotation: 'any',
BooleanTypeAnnotation: 'boolean',
MixedTypeAnnotation: 'mixed',
NullLiteralTypeAnnotation: 'null',
NumberTypeAnnotation: 'number',
StringTypeAnnotation: 'string',
VoidTypeAnnotation: 'void',
EmptyTypeAnnotation: 'empty'
};
const flowLiteralTypes = {
BooleanLiteralTypeAnnotation: 1,
NumberLiteralTypeAnnotation: 1,
StringLiteralTypeAnnotation: 1
};
const namedTypes = {
ArrayTypeAnnotation: handleArrayTypeAnnotation,
GenericTypeAnnotation: handleGenericTypeAnnotation,
ObjectTypeAnnotation: handleObjectTypeAnnotation,
InterfaceDeclaration: handleInterfaceDeclaration,
UnionTypeAnnotation: handleUnionTypeAnnotation,
NullableTypeAnnotation: handleNullableTypeAnnotation,
FunctionTypeAnnotation: handleFunctionTypeAnnotation,
IntersectionTypeAnnotation: handleIntersectionTypeAnnotation,
TupleTypeAnnotation: handleTupleTypeAnnotation,
TypeofTypeAnnotation: handleTypeofTypeAnnotation
};
function getFlowTypeWithRequirements(path, typeParams) {
const type = getFlowTypeWithResolvedTypes(path, typeParams);
type.required = !path.parentPath.node.optional;
return type;
}
function handleKeysHelper(path) {
let value = path.get('typeParameters', 'params', 0);
if (_astTypes.namedTypes.TypeofTypeAnnotation.check(value.node)) {
value = value.get('argument', 'id');
} else if (!_astTypes.namedTypes.ObjectTypeAnnotation.check(value.node)) {
value = value.get('id');
}
const resolvedPath = (0, _resolveToValue.default)(value);
if (resolvedPath && (_astTypes.namedTypes.ObjectExpression.check(resolvedPath.node) || _astTypes.namedTypes.ObjectTypeAnnotation.check(resolvedPath.node))) {
const keys = (0, _resolveObjectKeysToArray.resolveObjectToNameArray)(resolvedPath, true);
if (keys) {
return {
name: 'union',
raw: (0, _printValue.default)(path),
elements: keys.map(key => ({
name: 'literal',
value: key
}))
};
}
}
return null;
}
function handleArrayTypeAnnotation(path, typeParams) {
return {
name: 'Array',
elements: [getFlowTypeWithResolvedTypes(path.get('elementType'), typeParams)],
raw: (0, _printValue.default)(path)
};
}
function handleGenericTypeAnnotation(path, typeParams) {
if (path.node.id.name === '$Keys' && path.node.typeParameters) {
return handleKeysHelper(path);
}
let type;
if (_astTypes.namedTypes.QualifiedTypeIdentifier.check(path.node.id)) {
const id = path.get('id');
if (id.node.qualification.name === 'React') {
type = {
name: `${id.node.qualification.name}${id.node.id.name}`,
raw: (0, _printValue.default)(id)
};
} else {
type = {
name: (0, _printValue.default)(id).replace(/<.*>$/, '')
};
}
} else {
type = {
name: path.node.id.name
};
}
const resolvedPath = typeParams && typeParams[type.name] || (0, _resolveToValue.default)(path.get('id'));
if (path.node.typeParameters && resolvedPath.node.typeParameters) {
typeParams = (0, _getTypeParameters.default)(resolvedPath.get('typeParameters'), path.get('typeParameters'), typeParams);
}
if (typeParams && typeParams[type.name] && typeParams[type.name].value.type === _astTypes.namedTypes.GenericTypeAnnotation.name) {
return type;
}
if (typeParams && typeParams[type.name]) {
type = getFlowTypeWithResolvedTypes(resolvedPath, typeParams);
}
if (resolvedPath && resolvedPath.node.right) {
type = getFlowTypeWithResolvedTypes(resolvedPath.get('right'), typeParams);
} else if (path.node.typeParameters) {
const params = path.get('typeParameters').get('params');
type = { ...type,
elements: params.map(param => getFlowTypeWithResolvedTypes(param, typeParams)),
raw: (0, _printValue.default)(path)
};
}
return type;
}
function handleObjectTypeAnnotation(path, typeParams) {
const type = {
name: 'signature',
type: 'object',
raw: (0, _printValue.default)(path),
signature: {
properties: []
}
};
path.get('callProperties').each(param => {
type.signature.constructor = getFlowTypeWithResolvedTypes(param.get('value'), typeParams);
});
path.get('indexers').each(param => {
type.signature.properties.push({
key: getFlowTypeWithResolvedTypes(param.get('key'), typeParams),
value: getFlowTypeWithRequirements(param.get('value'), typeParams)
});
});
path.get('properties').each(param => {
if (_astTypes.namedTypes.ObjectTypeProperty.check(param.node)) {
type.signature.properties.push({
// For ObjectTypeProperties `getPropertyName` always returns string
key: (0, _getPropertyName.default)(param),
value: getFlowTypeWithRequirements(param.get('value'), typeParams)
});
} else if (_astTypes.namedTypes.ObjectTypeSpreadProperty.check(param.node)) {
let spreadObject = (0, _resolveToValue.default)(param.get('argument'));
if (_astTypes.namedTypes.GenericTypeAnnotation.check(spreadObject.node)) {
const typeAlias = (0, _resolveToValue.default)(spreadObject.get('id'));
if (_astTypes.namedTypes.ObjectTypeAnnotation.check(typeAlias.get('right').node)) {
spreadObject = (0, _resolveToValue.default)(typeAlias.get('right'));
}
}
if (_astTypes.namedTypes.ObjectTypeAnnotation.check(spreadObject.node)) {
const props = handleObjectTypeAnnotation(spreadObject, typeParams);
type.signature.properties.push(...props.signature.properties);
}
}
});
return type;
}
function handleInterfaceDeclaration(path) {
// Interfaces are handled like references which would be documented separately,
// rather than inlined like type aliases.
return {
name: path.node.id.name
};
}
function handleUnionTypeAnnotation(path, typeParams) {
return {
name: 'union',
raw: (0, _printValue.default)(path),
elements: path.get('types').map(subType => getFlowTypeWithResolvedTypes(subType, typeParams))
};
}
function handleIntersectionTypeAnnotation(path, typeParams) {
return {
name: 'intersection',
raw: (0, _printValue.default)(path),
elements: path.get('types').map(subType => getFlowTypeWithResolvedTypes(subType, typeParams))
};
}
function handleNullableTypeAnnotation(path, typeParams) {
const typeAnnotation = (0, _getTypeAnnotation.default)(path);
if (!typeAnnotation) return null;
const type = getFlowTypeWithResolvedTypes(typeAnnotation, typeParams);
type.nullable = true;
return type;
}
function handleFunctionTypeAnnotation(path, typeParams) {
const type = {
name: 'signature',
type: 'function',
raw: (0, _printValue.default)(path),
signature: {
arguments: [],
return: getFlowTypeWithResolvedTypes(path.get('returnType'), typeParams)
}
};
path.get('params').each(param => {
const typeAnnotation = (0, _getTypeAnnotation.default)(param);
type.signature.arguments.push({
name: param.node.name ? param.node.name.name : '',
type: typeAnnotation ? getFlowTypeWithResolvedTypes(typeAnnotation, typeParams) : undefined
});
});
if (path.node.rest) {
const rest = path.get('rest');
const typeAnnotation = (0, _getTypeAnnotation.default)(rest);
type.signature.arguments.push({
name: rest.node.name ? rest.node.name.name : '',
type: typeAnnotation ? getFlowTypeWithResolvedTypes(typeAnnotation, typeParams) : undefined,
rest: true
});
}
return type;
}
function handleTupleTypeAnnotation(path, typeParams) {
const type = {
name: 'tuple',
raw: (0, _printValue.default)(path),
elements: []
};
path.get('types').each(param => {
type.elements.push(getFlowTypeWithResolvedTypes(param, typeParams));
});
return type;
}
function handleTypeofTypeAnnotation(path, typeParams) {
return getFlowTypeWithResolvedTypes(path.get('argument'), typeParams);
}
let visitedTypes = {};
function getFlowTypeWithResolvedTypes(path, typeParams) {
const node = path.node;
let type;
const isTypeAlias = _astTypes.namedTypes.TypeAlias.check(path.parentPath.node); // When we see a typealias mark it as visited so that the next
// call of this function does not run into an endless loop
if (isTypeAlias) {
if (visitedTypes[path.parentPath.node.id.name] === true) {
// if we are currently visiting this node then just return the name
// as we are starting to endless loop
return {
name: path.parentPath.node.id.name
};
} else if (typeof visitedTypes[path.parentPath.node.id.name] === 'object') {
// if we already resolved the type simple return it
return visitedTypes[path.parentPath.node.id.name];
} // mark the type as visited
visitedTypes[path.parentPath.node.id.name] = true;
}
if (node.type in flowTypes) {
type = {
name: flowTypes[node.type]
};
} else if (node.type in flowLiteralTypes) {
type = {
name: 'literal',
value: node.raw || `${node.value}`
};
} else if (node.type in namedTypes) {
type = namedTypes[node.type](path, typeParams);
}
if (!type) {
type = {
name: 'unknown'
};
}
if (isTypeAlias) {
// mark the type as unvisited so that further calls can resolve the type again
visitedTypes[path.parentPath.node.id.name] = type;
}
return type;
}
/**
* Tries to identify the flow type by inspecting the path for known
* flow type names. This method doesn't check whether the found type is actually
* existing. It simply assumes that a match is always valid.
*
* If there is no match, "unknown" is returned.
*/
function getFlowType(path, typeParams) {
// Empty visited types before an after run
// Before: in case the detection threw and we rerun again
// After: cleanup memory after we are done here
visitedTypes = {};
const type = getFlowTypeWithResolvedTypes(path, typeParams);
visitedTypes = {};
return type;
}