in packages/eslint-plugin-baseui/src/deprecated-theme-api.js [436:555]
function lintUseStyletron(context, node) {
// Is there a useStyletron call in our current scope?
// Is the theme value captured from the call? Ex: const [css, theme] = useStyletron();
// - Is the theme value renamed? Ex: const [css, foo] = useStyletron();
// - Is the theme destructured? Ex: const [css, {colors}] = useStyletron();
// Is the current node invoked in a way that uses the theme in scope?
// - Ex: Full destructuring: foreground
// - Ex: Concern destructuring: colors.foreground
// const ancestors = context.getAncestors();
const scope = context.getScope();
const themeProperty = deprecatedThemeProperties[node.name];
if (scope.type === 'function' && scope.block.body.body) {
// Find all the variable declarations in the function body.
const declarations = scope.block.body.body.filter(
(statement) => statement.type === 'VariableDeclaration'
);
// Map of variable declaration types and properties:
// const [css, theme] = useStyletron()
// ^..........^ .id (ArrayPattern)
// ^............^ .init (CallExpression)
// ^...........................^ VariableDeclarator
// ^.................................^ VariableDeclaration
// Search each declaration for a declarator that invokes
// useStyletron as the initial value. This declarator
// will have all the information we need.
let declarator;
declarations.forEach((declaration) => {
declarator = declaration.declarations.find(
(declarator) =>
declarator.type === 'VariableDeclarator' &&
declarator.init &&
declarator.init.type === 'CallExpression' &&
declarator.init.callee.name === 'useStyletron'
);
});
if (!declarator) {
return false;
}
if (declarator.id.type === 'ArrayPattern' && declarator.id.elements.length === 2) {
// Confirm we are accessing the theme index in the returned array.
// Ex: const [css, theme] = useStyletron();
// Ex: const [css, {colors}] = useStyletron();
const themeIndexNode = declarator.id.elements[1];
if (themeIndexNode.type === 'Identifier') {
// This implies we are not destructuring the theme object (here at least).
const localThemeObjectName = themeIndexNode.name;
if (
node.parent.type === 'MemberExpression' &&
node.parent.object.type === 'MemberExpression' &&
node.parent.object.property.name === themeProperty.concern &&
node.parent.object.object.type === 'Identifier' &&
node.parent.object.object.name === localThemeObjectName
) {
// We have verified that the identifier accesses the theme.
// Ex: theme.colors.foreground
return true;
}
}
if (themeIndexNode.type === 'ObjectPattern') {
// Our theme object is being destructured.
// Check if we are destructuring the theme concern.
// Ex: const [css, {colors}] = useStyletron();
// Ex: const [css, {colors: foo}] = useStyletron();
const concernPropertyNode = themeIndexNode.properties.find(
(property) => property.key.name === themeProperty.concern
);
// TODO(refactor): check if lintStyleFunction can also use this:
// > node.parent.object.name === concernPropertyNode.value.name
if (
concernPropertyNode &&
// Ensure we are not destructuring further
concernPropertyNode.value.type === 'Identifier' &&
node.parent.type === 'MemberExpression' &&
node.parent.object.type === 'Identifier' &&
node.parent.object.name === concernPropertyNode.value.name
) {
// We have verified that the identifier accesses the "concern".
// Ex: colors.foreground
return true;
}
if (concernPropertyNode && concernPropertyNode.value.type === 'ObjectPattern') {
// We are destructuring even further!
// Check if we are destructuring the deprecated property in question.
// Ex: const [css, {colors: {foreground}}] = useStyletron();
// Ex: const [css, {colors: {foreground: foo}}] = useStyletron();
const deprecatedProperty = concernPropertyNode.value.properties.find(
(property) => property.key.name === node.name
);
// TODO(refactor): The conditional below is pretty confusing.
// We should break it up a bit. Also it is exactly the same as
// the final destructuring logic in lintStyleFunction...
if (
deprecatedProperty &&
(node === deprecatedProperty.key ||
(node !== deprecatedProperty.value && node.parent.type !== 'MemberExpression'))
) {
return true;
}
}
}
}
}
// If we've reached here then we can't flag anything.
return false;
}