not-an-aardvark / eslint-rule-composer

A utility for composing ESLint rules from other ESLint rules
MIT License
56 stars 2 forks source link

filterReports by parsing sourceCode. #4

Open DianaSuvorova opened 5 years ago

DianaSuvorova commented 5 years ago

Hello,

I am looking for a help. I am trying to use filterReports, although my predicate function has to be a bit more involved then any readme example or tests I saw in the lib. I actually need to parse a whole sourceCode in similar way I would have parsed for a eslint rule.

Here is somewhat pseudocode to illustrate what I need.

const ruleComposer = require('eslint-rule-composer');

const noUnusedPropTypesReact = require('eslint-plugin-react').rules['no-unused-prop-types'];

const getPropsUsedInRedux = (sourceCode) => {
  const usedInRedux = [];

  somehowRunThis({
    FunctionDeclaration(node) {
      if (node.id && node.id.name === 'mapDispatchToProps') {
        usedInRedux.push[node.body];
      }
    },
  });

  return usedInRedux;
};

module.exports = ruleComposer.filterReports(
  noUnusedPropTypesReact,
  (problem, metadata) => {
    const usedInRedux = getPropsUsedInRedux(metadata.sourceCode);
    return !usedInRedux.contains(problem.node)
  },
);

It seems like I need some combination of filterReports and joinReports. Or maybe there is some other obvious way or another util I can use. Would be very grateful for any suggestions.

Thanks, Diana

not-an-aardvark commented 5 years ago

Hi, thanks for creating an issue.

Would it work to put the mapDispatchToProps check inside the filterReports call? Then you wouldn't need to have the separate FunctionDeclaration listener.

module.exports = ruleComposer.filterReports(
  noUnusedPropTypesReact,
  (problem, metadata) => {
    const node = problem.node;
    if (node.parent.body !== node) {
        return true;
    }
    return !(node.parent.id && node.parent.id.name === 'mapDispatchToProps');
  },
);
DianaSuvorova commented 5 years ago

I do need that FunctionDeclaration listener and some others. I pretty much need to filter result of one rule by the result of another rule. Just problem.node is not enough, I need to analyze whole sourceCode to make a decision.

Here is particular issue I am working on: https://github.com/DianaSuvorova/eslint-plugin-react-redux/issues/28

DianaSuvorova commented 5 years ago

I have created a function for what I need to get done.

It unfortunately requires a lot of helper functions copied from your lib and might not be generic enough, but it works for my purpose. I will follow up if I get to cleaning it up, so I can offer it as a contribution for your library.

const filterReports = (rule, filterNode, filterAll) => Object.freeze({
  create(context) {
    const removeNodesFromReport = [];
    let allNodesFiltered = false;
    return getRuleCreateFunc(rule)(Object.freeze(Object.create(
      context,
      {
        report: {
          enumerable: true,
          value() {
            const reportDescriptor = getReportNormalizer(rule)(...arguments);
            if (filterAll(reportDescriptor)) {
              allNodesFiltered = true;
            }
            if (filterNode(reportDescriptor)) {
              removeNodesFromReport.push(reportDescriptor.node);
            } else if (!allNodesFiltered && !removeNodesFromReport.includes(reportDescriptor.node)) {
              context.report(removeMessageIfMessageIdPresent(reportDescriptor));
            }
          },
        },
      },
    )));
  },
  schema: rule.schema,
  meta: getRuleMeta(rule),
});

module.exports = (rules, filterNode, filterAll) => filterReports(ruleComposer.joinReports(rules), filterNode, filterAll);

Thanks a lot for creating this library - it was super helpful for me! Diana