Skip to content

Commit

Permalink
feat: allow methods on objects
Browse files Browse the repository at this point in the history
Closes #15
  • Loading branch information
JamieMason committed Jan 9, 2025
1 parent 0021931 commit b272a2b
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Add the plugin to the `plugins` section and the rule to the `rules` section in y
{
"allowedNames": [],
"allowNamedFunctions": false,
"allowObjectProperties": false,
"classPropertiesAllowed": false,
"disallowPrototype": false,
"returnStyle": "unchanged",
Expand All @@ -41,6 +42,16 @@ An optional array of function names to ignore. When set, the rule won't report n

If set to true, the rule won't report named functions such as `function foo() {}`. Anonymous function such as `const foo = function() {}` will still be reported.

### `allowObjectProperties`

If set to true, the rule won't report named methods such as

```js
const myObj = {
hello() {}
}
```

### `classPropertiesAllowed`

When `true`, functions defined as [class instance fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Field_declarations) will be converted to arrow functions when doing so would not alter or break their behaviour.
Expand Down
2 changes: 2 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface Scope {
export interface ActualOptions {
allowedNames: string[];
allowNamedFunctions: boolean;
allowObjectProperties: boolean;
classPropertiesAllowed: boolean;
disallowPrototype: boolean;
returnStyle: 'explicit' | 'implicit' | 'unchanged';
Expand All @@ -28,6 +29,7 @@ export interface ActualOptions {
export const DEFAULT_OPTIONS: ActualOptions = {
allowedNames: [],
allowNamedFunctions: false,
allowObjectProperties: false,
classPropertiesAllowed: false,
disallowPrototype: false,
returnStyle: 'unchanged',
Expand Down
10 changes: 10 additions & 0 deletions src/guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ export class Guard {
return this.isNamedFunction(fn) && this.options.allowedNames.includes(fn.id.name);
}

isObjectProperty(fn: AnyFunction): boolean {
return this.sourceCode
.getAncestors(fn)
.reverse()
.some((ancestor) => {
return ancestor.type === AST_NODE_TYPES.Property;
});
}

isSafeTransformation(fn: TSESTree.Node): fn is AnyFunction {
const isSafe =
this.isAnyFunction(fn) &&
Expand All @@ -178,6 +187,7 @@ export class Guard {
if (this.options.allowNamedFunctions && this.isNamedFunction(fn)) return false;
if (!this.options.disallowPrototype && this.isPrototypeAssignment(fn)) return false;
if (this.options.singleReturnOnly && !this.returnsImmediately(fn)) return false;
if (this.isObjectProperty(fn) && this.options.allowObjectProperties) return false;
if (this.hasNameAndIsExportedAsDefaultExport(fn)) return false;
return true;
}
Expand Down
4 changes: 4 additions & 0 deletions src/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export const preferArrowFunctions = createRule<Options, MessageId>({
default: DEFAULT_OPTIONS.allowNamedFunctions,
type: 'boolean',
},
allowObjectProperties: {
default: DEFAULT_OPTIONS.allowObjectProperties,
type: 'boolean',
},
classPropertiesAllowed: {
default: DEFAULT_OPTIONS.classPropertiesAllowed,
type: 'boolean',
Expand Down
29 changes: 29 additions & 0 deletions test/rule.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,35 @@ describe('when classPropertiesAllowed is true', () => {
});
});

describe('allowObjectProperties', () => {
describe('when property can be converted to an arrow function', () => {
describe('leaves the method as is when allowObjectProperties is true', () => {
ruleTester.run('prefer-arrow-functions', rule, {
valid: [
{
code: 'const foo = { render(a, b) { console.log(3); } }',
},
{
code: 'export default { data(){ return 4 } }',
},
].map(withOptions({ allowObjectProperties: true })),
invalid: [
{
code: 'const foo = { render(a, b) { return a + b; } }',
output: 'const foo = { render: (a, b) => a + b }',
},
{
code: 'export default { data(){ return 4 } }',
output: 'export default { data: () => 4 }',
},
]
.map(withOptions({ allowObjectProperties: false }))
.map(withErrors(['USE_ARROW_WHEN_FUNCTION'])),
});
});
});
});

describe('when singleReturnOnly is true', () => {
describe('when function should be an arrow function', () => {
describe('when function does not contain only a return statement', () => {
Expand Down

0 comments on commit b272a2b

Please sign in to comment.