in packages/eui/scripts/babel/proptypes-from-ts-props/index.js [1492:1611]
VariableDeclarator: function visitVariableDeclarator(nodePath, state) {
// only process typescript files
if (
path.extname(state.file.opts.filename) !== '.ts' &&
path.extname(state.file.opts.filename) !== '.tsx'
)
return;
const resolveVariableDeclarator = (variableDeclarator) => {
const { id } = variableDeclarator;
const idTypeAnnotation = id.typeAnnotation;
let fileCodeNeedsUpdating = false;
if (
// this is a function call
types.isCallExpression(variableDeclarator.init) &&
// is this forwardRef()
((types.isIdentifier(variableDeclarator.init.callee) &&
variableDeclarator.init.callee.name === 'forwardRef' &&
variableDeclarator.init.typeParameters &&
variableDeclarator.init.typeParameters.params.length === 2) ||
// or is this React.forwardRef()
(types.isMemberExpression(variableDeclarator.init.callee) &&
types.isIdentifier(variableDeclarator.init.callee.object) &&
variableDeclarator.init.callee.object.name === 'React' &&
types.isIdentifier(variableDeclarator.init.callee.property) &&
variableDeclarator.init.callee.property.name === 'forwardRef'))
) {
// props for the component come from the second argument to the type params
const typeDefinition =
variableDeclarator.init.typeParameters.params[1];
fileCodeNeedsUpdating = true;
processComponentDeclaration(typeDefinition, nodePath, state);
} else if (idTypeAnnotation) {
if (idTypeAnnotation.typeAnnotation.type === 'TSTypeReference') {
if (
idTypeAnnotation.typeAnnotation.typeName.type ===
'TSQualifiedName'
) {
const { left, right } =
idTypeAnnotation.typeAnnotation.typeName;
if (left.name === 'React') {
const rightName = right.name;
if (
rightName === 'SFC' ||
rightName === 'FunctionComponent'
) {
processComponentDeclaration(
idTypeAnnotation.typeAnnotation.typeParameters.params[0],
nodePath,
state
);
fileCodeNeedsUpdating = true;
} else {
// throw new Error(`Cannot process annotation id React.${right.name}`);
}
}
} else if (
idTypeAnnotation.typeAnnotation.typeName.type === 'Identifier'
) {
const typeName = idTypeAnnotation.typeAnnotation.typeName.name;
if (typeName === 'SFC' || typeName === 'FunctionComponent') {
if (state.get('importsFromReact').has(typeName)) {
// Declarations like `const Foo: FunctionComponent`
// don't have type parameters. It's a valid declaration
// because the generic argument has a default of empty
// props.
if (idTypeAnnotation.typeAnnotation.typeParameters) {
processComponentDeclaration(
idTypeAnnotation.typeAnnotation.typeParameters
.params[0],
nodePath,
state
);
fileCodeNeedsUpdating = true;
}
}
} else {
// reprocess this variable declaration but use the identifier lookup
const nextTypeDefinition =
state.get('typeDefinitions')[typeName];
const types = state.get('types');
if (
nextTypeDefinition &&
types.isTSType(nextTypeDefinition)
) {
const newId = types.cloneDeep(id);
newId.typeAnnotation =
types.TSTypeAnnotation(nextTypeDefinition);
const newNode = types.VariableDeclarator(
newId,
variableDeclarator.init
);
resolveVariableDeclarator(newNode);
}
}
} else {
throw new Error(
'Cannot process annotation type of',
idTypeAnnotation.typeAnnotation.id.type
);
}
}
}
if (fileCodeNeedsUpdating) {
// babel-plugin-react-docgen passes `this.file.code` to react-docgen
// instead of using the modified AST; to expose our changes to react-docgen
// they need to be rendered to a string
this.file.code = stripTypeScript(
this.file.opts.filename,
this.file.ast
);
}
};
// kick off the recursive search for a React component in this node
resolveVariableDeclarator(nodePath.node);
},