Skip to content

Commit

Permalink
[Refactor] improve performance of rule merging
Browse files Browse the repository at this point in the history
  • Loading branch information
golopot authored and ljharb committed May 2, 2022
1 parent c8833f3 commit 438c21a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 32 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -31,7 +31,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [Refactor] improve performance by avoiding unnecessary `Components.detect` ([#3273][] @golopot)
* [Refactor] add `isParenthesized` AST util ([#3203][] @Belco90)
* [Docs] `default-props-match-prop-types`, `require-default-props`, `sort-prop-types`: fix typos ([#3279][] @nix6839)
* [Refactor] improve performance of rule merging ([#3281][] @golopot)

[#3281]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3281
[#3280]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3280
[#3279]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3279
[#3273]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3273
Expand Down
74 changes: 42 additions & 32 deletions lib/util/Components.js
Expand Up @@ -247,6 +247,39 @@ function getWrapperFunctions(context, pragma) {
]);
}

// eslint-disable-next-line valid-jsdoc
/**
* Merge many eslint rules into one
* @param {{[_: string]: Function}[]} rules the returned values for eslint rule.create(context)
* @returns {{[_: string]: Function}} merged rule
*/
function mergeRules(rules) {
/** @type {Map<string, Function[]>} */
const handlersByKey = new Map();
rules.forEach((rule) => {
Object.keys(rule).forEach((key) => {
const fns = handlersByKey.get(key);
if (!fns) {
handlersByKey.set(key, [rule[key]]);
} else {
fns.push(rule[key]);
}
});
});

/** @type {{[key: string]: Function}} */
const rule = {};
handlersByKey.forEach((fns, key) => {
rule[key] = function mergedHandler(node) {
fns.forEach((fn) => {
fn(node);
});
};
});

return rule;
}

function componentRule(rule, context) {
const pragma = pragmaUtil.getFromContext(context);
const sourceCode = context.getSourceCode();
Expand Down Expand Up @@ -859,44 +892,21 @@ function componentRule(rule, context) {
},
};

// Update the provided rule instructions to add the component detection
const ruleInstructions = rule(context, components, utils);
const updatedRuleInstructions = Object.assign({}, ruleInstructions);
const propTypesInstructions = propTypesUtil(context, components, utils);
const usedPropTypesInstructions = usedPropTypesUtil(context, components, utils);
const defaultPropsInstructions = defaultPropsUtil(context, components, utils);
const allKeys = new Set(Object.keys(detectionInstructions).concat(
Object.keys(propTypesInstructions),
Object.keys(usedPropTypesInstructions),
Object.keys(defaultPropsInstructions),
Object.keys(reactImportInstructions)
));

allKeys.forEach((instruction) => {
updatedRuleInstructions[instruction] = (node) => {
if (instruction in detectionInstructions) {
detectionInstructions[instruction](node);
}
if (instruction in propTypesInstructions) {
propTypesInstructions[instruction](node);
}
if (instruction in usedPropTypesInstructions) {
usedPropTypesInstructions[instruction](node);
}
if (instruction in defaultPropsInstructions) {
defaultPropsInstructions[instruction](node);
}
if (instruction in reactImportInstructions) {
reactImportInstructions[instruction](node);
}
if (ruleInstructions[instruction]) {
return ruleInstructions[instruction](node);
}
};
});
const mergedRule = mergeRules([
detectionInstructions,
propTypesInstructions,
usedPropTypesInstructions,
defaultPropsInstructions,
reactImportInstructions,
ruleInstructions,
]);

// Return the updated rule instructions
return updatedRuleInstructions;
return mergedRule;
}

module.exports = Object.assign(Components, {
Expand Down

0 comments on commit 438c21a

Please sign in to comment.