formatjs/formatjs-old

Detect destructured formatMessage usage

fsmaia opened this issue · 6 comments

Which package?
babel-plugin-react-intl

Is your feature request related to a problem? Please describe.
When using formatMessage by destructuring intl, like in the following snippet, it isn't detected by the plugin:

const { formatMessage } = intl;
formatMessage({ id: 'id' });

Describe the solution you'd like
Although intrusive, we could check for all the formatMessage callees, as a kind of reserved word.

Describe alternatives you've considered

  • Removing all intl destructuring
  • Extending this plugin to receive an isFormatMessageCall function as configuration
  • Trying to improve this rule by detecting destructuring inside babel

A way to achieve it would be performing the following verification inside isFormatMessageCall:

callee.isIdentifier() && callee.node.name === 'formatMessage'

To improve the rule, we could check the callee scope to find expressions like:

const { intl: { formatMessage } } = this.props;
const { formatMessage } = intl;

Any suggestions?

it's technically possible you would need to make sure references are kept track of properly, e.g const {formatMessage: f} = intl

PR's always welcome :) along w/ test cases to demo your use case

I solved the biggest part of the problem, by detecting const { intl: { formatMessage } } = this.props in class components, and destructured usaged in stateless components, with the following excerpt:

function isFormatMessageDestructuring(scope: Scope) {
  const binding = scope.getBinding('formatMessage');
  const block = scope.block as t.FunctionDeclaration;

  if (binding && t.isVariableDeclarator(binding.path.node)) {
    const nodeObject = binding.path.node.id as ObjectPattern;
    return nodeObject.properties.find(
      (value: any) => value.key.name === 'intl'
    );
  }

  if (t.isObjectPattern(block.params[0])) {
    return block.params[0].properties.find(
      (value: any) => value.key.name === 'intl'
    );
  }

  return false;
}

function isFormatMessageCall(
  callee: NodePath<Expression | V8IntrinsicIdentifier>,
  path: any
) {
  if (
    callee.isIdentifier() &&
    callee.node.name === 'formatMessage' &&
    isFormatMessageDestructuring(path.scope)
  ) {
    return true;
  }

  //..

Now I'm missing const { props: { intl: { formatMessage } } } = this pattern.

So close :)

you prob will have to handle aliasing as well, e.g {formatMesage: _} = intl or something like that