@linaria/utils
Version:
Blazing fast zero-runtime CSS in JS library
62 lines (58 loc) • 2.03 kB
JavaScript
import { getScope } from './getScope';
function isInUnary(path) {
return path.parentPath?.isUnaryExpression() ?? false;
}
// It's possible for non-strict mode code to have variable deletions.
function isInDelete(path) {
return path.parentPath.node.operator === 'delete';
}
function isBindingIdentifier(path) {
return path.isBindingIdentifier() && (!isInUnary(path) || isInDelete(path));
}
function isReferencedIdentifier(path) {
return path.isReferencedIdentifier() || isInUnary(path) && !isInDelete(path);
}
// For some reasons, `isBindingIdentifier` returns true for identifiers inside unary expressions.
const checkers = {
any: ex => isBindingIdentifier(ex) || isReferencedIdentifier(ex),
binding: ex => isBindingIdentifier(ex),
declaration: ex => isBindingIdentifier(ex) && ex.scope.getBinding(ex.node.name)?.identifier === ex.node,
reference: ex => isReferencedIdentifier(ex)
};
export function nonType(path) {
return !path.find(p => p.isTSTypeReference() || p.isTSTypeQuery() || p.isFlowType() || p.isFlowDeclaration() || p.isTSInterfaceDeclaration());
}
export default function findIdentifiers(expressions, type = 'reference') {
const identifiers = [];
expressions.forEach(ex => {
const emit = path => {
if (!path.node || path.removed || !checkers[type](path)) {
return;
}
// TODO: Is there a better way to check that it's a local variable?
const binding = getScope(path).getBinding(path.node.name);
if (!binding) {
return;
}
if (type === 'reference' && ex.isAncestor(binding.path)) {
// This identifier is declared inside the expression. We don't need it.
return;
}
identifiers.push(path);
};
if (ex.isIdentifier() || ex.isJSXIdentifier()) {
emit(ex);
} else {
ex.traverse({
Identifier(path) {
emit(path);
},
JSXIdentifier(path) {
emit(path);
}
});
}
});
return identifiers;
}
//# sourceMappingURL=findIdentifiers.js.map