-
Notifications
You must be signed in to change notification settings - Fork 17
SHARD-2733 updated linting setup and rules. Added rule for unused pure functions #551
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
base: dev
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| const noUnusedPureCalls = require('./rules/no-unused-pure-calls'); | ||
|
|
||
| module.exports = { | ||
| rules: { | ||
| 'no-unused-pure-calls': noUnusedPureCalls, | ||
| }, | ||
| configs: { | ||
| recommended: { | ||
| plugins: ['pure-functions'], | ||
| rules: { | ||
| 'pure-functions/no-unused-pure-calls': 'error', | ||
| }, | ||
| }, | ||
| }, | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,173 @@ | ||||||
| module.exports = { | ||||||
| meta: { | ||||||
| type: 'problem', | ||||||
| docs: { | ||||||
| description: 'Disallow calling pure functions without using their return value', | ||||||
| category: 'Possible Errors', | ||||||
| recommended: true, | ||||||
| }, | ||||||
| fixable: 'code', | ||||||
| hasSuggestions: true, | ||||||
| schema: [ | ||||||
| { | ||||||
| type: 'object', | ||||||
| properties: { | ||||||
| pureMethods: { | ||||||
| type: 'array', | ||||||
| items: { type: 'string' }, | ||||||
| default: [], | ||||||
| }, | ||||||
| }, | ||||||
| additionalProperties: false, | ||||||
| }, | ||||||
| ], | ||||||
| messages: { | ||||||
| unusedPureCall: "Pure method '{{method}}' called without using return value. Did you mean to assign the result?", | ||||||
| }, | ||||||
| }, | ||||||
|
|
||||||
| create(context) { | ||||||
| // Default pure methods that don't mutate the original object/array | ||||||
| const defaultPureMethods = [ | ||||||
| // Array methods that return new arrays | ||||||
| 'concat', | ||||||
| 'slice', | ||||||
| 'map', | ||||||
| 'filter', | ||||||
| 'reduce', | ||||||
| 'reduceRight', | ||||||
| 'find', | ||||||
| 'findIndex', | ||||||
| 'some', | ||||||
| 'every', | ||||||
| 'includes', | ||||||
| 'indexOf', | ||||||
| 'lastIndexOf', | ||||||
| 'join', | ||||||
| 'toString', | ||||||
| 'toLocaleString', | ||||||
| 'flatMap', | ||||||
| 'flat', | ||||||
| 'with', | ||||||
| 'toReversed', | ||||||
| 'toSorted', | ||||||
| 'toSpliced', | ||||||
|
|
||||||
| // String methods that return new strings | ||||||
| 'substring', | ||||||
| 'substr', | ||||||
| 'toLowerCase', | ||||||
| 'toUpperCase', | ||||||
| 'trim', | ||||||
| 'trimStart', | ||||||
| 'trimEnd', | ||||||
| 'replace', | ||||||
| 'replaceAll', | ||||||
| 'split', | ||||||
| 'padStart', | ||||||
| 'padEnd', | ||||||
| 'repeat', | ||||||
| 'charAt', | ||||||
| 'charCodeAt', | ||||||
| 'slice', | ||||||
| 'substr', | ||||||
| 'substring', | ||||||
|
|
||||||
| // Object methods that return new objects/values | ||||||
| 'assign', | ||||||
| 'keys', | ||||||
| 'values', | ||||||
| 'entries', | ||||||
| 'freeze', | ||||||
| 'seal', | ||||||
| 'getOwnPropertyNames', | ||||||
| 'getOwnPropertyDescriptors', | ||||||
| 'sign', | ||||||
| ] | ||||||
|
|
||||||
| const options = context.options[0] || {} | ||||||
| const pureMethods = [...defaultPureMethods, ...(options.pureMethods || [])] | ||||||
|
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. Suggestion: The
Suggested change
|
||||||
|
|
||||||
| function isPureMethodCall(node) { | ||||||
| if (node.type !== 'CallExpression') return false | ||||||
| if (node.callee.type !== 'MemberExpression') return false | ||||||
| if (node.callee.property.type !== 'Identifier') return false | ||||||
|
|
||||||
| return pureMethods.includes(node.callee.property.name) | ||||||
| } | ||||||
|
|
||||||
| function isResultUsed(node) { | ||||||
| const parent = node.parent | ||||||
|
|
||||||
| // Check if return value is used in meaningful way | ||||||
| switch (parent.type) { | ||||||
| case 'AssignmentExpression': | ||||||
| return parent.right === node | ||||||
| case 'VariableDeclarator': | ||||||
| return parent.init === node | ||||||
| case 'ReturnStatement': | ||||||
| return true | ||||||
| case 'CallExpression': | ||||||
| return parent.arguments.includes(node) | ||||||
| case 'BinaryExpression': | ||||||
| case 'LogicalExpression': | ||||||
| case 'UnaryExpression': | ||||||
| return true | ||||||
| case 'ConditionalExpression': | ||||||
| return parent.test === node || parent.consequent === node || parent.alternate === node | ||||||
| case 'ArrayExpression': | ||||||
| return parent.elements.includes(node) | ||||||
| case 'ObjectExpression': | ||||||
| return parent.properties.some((prop) => prop.value === node) | ||||||
| case 'Property': | ||||||
| return parent.value === node | ||||||
| case 'IfStatement': | ||||||
| return parent.test === node | ||||||
| case 'WhileStatement': | ||||||
| case 'ForStatement': | ||||||
| return parent.test === node | ||||||
| case 'ExpressionStatement': | ||||||
| return false // This is the problem case - standalone expression | ||||||
| case 'AwaitExpression': | ||||||
| return parent.argument === node | ||||||
| default: | ||||||
| return true // Assume used in other contexts | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| return { | ||||||
| ExpressionStatement(node) { | ||||||
| const expression = node.expression | ||||||
|
|
||||||
| if (isPureMethodCall(expression) && !isResultUsed(expression)) { | ||||||
| const methodName = expression.callee.property.name | ||||||
|
|
||||||
| context.report({ | ||||||
| node: expression, | ||||||
| messageId: 'unusedPureCall', | ||||||
| data: { | ||||||
| method: methodName, | ||||||
| }, | ||||||
| suggest: [ | ||||||
| { | ||||||
| desc: 'Assign result to variable', | ||||||
| fix(fixer) { | ||||||
| const sourceCode = context.getSourceCode() | ||||||
| const objectText = sourceCode.getText(expression.callee.object) | ||||||
| const methodCall = sourceCode.getText(expression) | ||||||
|
|
||||||
| // Suggest assignment back to the same variable if possible | ||||||
| if (expression.callee.object.type === 'Identifier') { | ||||||
| return fixer.replaceText(node, `${objectText} = ${methodCall};`) | ||||||
| } else { | ||||||
| return fixer.replaceText(node, `const result = ${methodCall};`) | ||||||
| } | ||||||
| }, | ||||||
| }, | ||||||
| ], | ||||||
| }) | ||||||
| } | ||||||
| }, | ||||||
| } | ||||||
| }, | ||||||
| } | ||||||
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.
Suggestion: The
defaultPureMethodsarray includes 'assign', which is not a pure function (Object.assign mutates the first argument). Remove 'assign' to avoid false positives where mutating methods are flagged as pure. [possible issue, importance: 9]