-
-
Notifications
You must be signed in to change notification settings - Fork 30
Breaking: Add support for TypeScript rules #197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,7 +86,24 @@ function isRuleTesterConstruction (node) { | |
const INTERESTING_RULE_KEYS = new Set(['create', 'meta']); | ||
|
||
/** | ||
* Helper for `getRuleInfo`. Handles ESM rules. | ||
* Collect properties from an object that have interesting key names into a new object | ||
* @param {Node[]} properties | ||
* @param {Set<String>} interestingKeys | ||
* @returns Object | ||
*/ | ||
function collectInterestingProperties (properties, interestingKeys) { | ||
// eslint-disable-next-line unicorn/prefer-object-from-entries | ||
return properties.reduce((parsedProps, prop) => { | ||
const keyValue = module.exports.getKeyName(prop); | ||
if (interestingKeys.has(keyValue)) { | ||
parsedProps[keyValue] = prop.value; | ||
} | ||
return parsedProps; | ||
}, {}); | ||
} | ||
|
||
/** | ||
* Helper for `getRuleInfo`. Handles ESM and TypeScript rules. | ||
*/ | ||
function getRuleExportsESM (ast) { | ||
return ast.body | ||
|
@@ -95,16 +112,29 @@ function getRuleExportsESM (ast) { | |
// eslint-disable-next-line unicorn/prefer-object-from-entries | ||
.reduce((currentExports, node) => { | ||
if (node.type === 'ObjectExpression') { | ||
// eslint-disable-next-line unicorn/prefer-object-from-entries | ||
return node.properties.reduce((parsedProps, prop) => { | ||
const keyValue = module.exports.getKeyName(prop); | ||
if (INTERESTING_RULE_KEYS.has(keyValue)) { | ||
parsedProps[keyValue] = prop.value; | ||
} | ||
return parsedProps; | ||
}, {}); | ||
// Check `export default { create() {}, meta: {} }` | ||
return collectInterestingProperties(node.properties, INTERESTING_RULE_KEYS); | ||
} else if (isNormalFunctionExpression(node)) { | ||
// Check `export default function() {}` | ||
return { create: node, meta: null, isNewStyle: false }; | ||
} else if ( | ||
node.type === 'CallExpression' && | ||
node.typeParameters && | ||
node.typeParameters.params.length === 2 && // Expecting: <Options, MessageIds> | ||
node.arguments.length === 1 && | ||
node.arguments[0].type === 'ObjectExpression' && | ||
// Check various TypeScript rule helper formats. | ||
( | ||
// createESLintRule({ ... }) | ||
node.callee.type === 'Identifier' || | ||
// util.createRule({ ... }) | ||
(node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.property.type === 'Identifier') || | ||
// ESLintUtils.RuleCreator(docsUrl)({ ... }) | ||
(node.callee.type === 'CallExpression' && node.callee.callee.type === 'MemberExpression' && node.callee.callee.object.type === 'Identifier' && node.callee.callee.property.type === 'Identifier') | ||
) | ||
) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems likely to cause some false positives. I was wondering if we can support a new setting like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Requiring the user to have to configure a global .eslintrc.js setting for all these rules to work is a high barrier-to-entry that I would like to avoid. Perhaps as an optional setting for users with a custom util function, but not required. Right now, I do believe the chance of false positives is actually very low, given:
That said, I'm more than happy to try to make this TypeScript rule check more strict to further reduce the potential for false positives if we discover any additional import/type/other information we can cue off of. Let me know if you have ideas. But as is, I do believe that the existing checks are more-than-sufficient, and that we could treat any improvements as bug fixes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well, it also makes sense! |
||
// Check `export default someTypeScriptHelper({ create() {}, meta: {} }); | ||
return collectInterestingProperties(node.arguments[0].properties, INTERESTING_RULE_KEYS); | ||
} | ||
return currentExports; | ||
}, {}); | ||
|
@@ -136,14 +166,7 @@ function getRuleExportsCJS (ast) { | |
} else if (node.right.type === 'ObjectExpression') { | ||
// Check `module.exports = { create: function () {}, meta: {} }` | ||
|
||
// eslint-disable-next-line unicorn/prefer-object-from-entries | ||
return node.right.properties.reduce((parsedProps, prop) => { | ||
const keyValue = module.exports.getKeyName(prop); | ||
if (INTERESTING_RULE_KEYS.has(keyValue)) { | ||
parsedProps[keyValue] = prop.value; | ||
} | ||
return parsedProps; | ||
}, {}); | ||
return collectInterestingProperties(node.right.properties, INTERESTING_RULE_KEYS); | ||
} | ||
return {}; | ||
} else if ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note that it's not required that you declare type parameters.
In general - we are lazy and avoid declaring the type arguments if there are no options (example).
If there are no options then TS can infer
[]
as the options type, and it can infer the messageIds from the object literal definition.Ideally as well you wouldn't ever need to declare two parameters... but that's a problem with TS (there's no way to tell TS "use this explicit generic and infer the second generic) :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bradzacher based on what you're telling me here, I'll remove the check for the type parameters to avoid false negatives. Let me know if there are any other common TS rule formats to support or other cues we can use to more-accurately detect TypeScript rules.