diff --git a/.README/rules/require-jsdoc.md b/.README/rules/require-jsdoc.md index b04e380ef..857dfd234 100644 --- a/.README/rules/require-jsdoc.md +++ b/.README/rules/require-jsdoc.md @@ -73,11 +73,19 @@ no parameters or return values are found. ##### `checkGetters` -A value indicating whether getters should be checked. Defaults to `false`. +A value indicating whether getters should be checked. Besides setting as a +boolean, this option can be set to the string `"no-setter"` to indicate that +getters should be checked but only when there is no setter. This may be useful +if one only wishes documentation on one of the two accessors. Defaults to +`false`. ##### `checkSetters` -A value indicating whether setters should be checked. Defaults to `false`. +A value indicating whether setters should be checked. Besides setting as a +boolean, this option can be set to the string `"no-getter"` to indicate that +setters should be checked but only when there is no getter. This may be useful +if one only wishes documentation on one of the two accessors. Defaults to +`false`. ##### `enableFixer` diff --git a/README.md b/README.md index 0c19b8472..e42906ad2 100644 --- a/README.md +++ b/README.md @@ -10064,12 +10064,20 @@ no parameters or return values are found. ##### checkGetters -A value indicating whether getters should be checked. Defaults to `false`. +A value indicating whether getters should be checked. Besides setting as a +boolean, this option can be set to the string `"no-setter"` to indicate that +getters should be checked but only when there is no setter. This may be useful +if one only wishes documentation on one of the two accessors. Defaults to +`false`. ##### checkSetters -A value indicating whether setters should be checked. Defaults to `false`. +A value indicating whether setters should be checked. Besides setting as a +boolean, this option can be set to the string `"no-getter"` to indicate that +setters should be checked but only when there is no getter. This may be useful +if one only wishes documentation on one of the two accessors. Defaults to +`false`. ##### enableFixer @@ -10761,6 +10769,24 @@ requestAnimationFrame(draw) function bench() { } // Message: Missing JSDoc comment. + +class Foo { + set aName (val) {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkSetters":"no-getter","contexts":["MethodDefinition > FunctionExpression"]}] +// Message: Missing JSDoc comment. + +class Foo { + get aName () {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkGetters":"no-setter","contexts":["MethodDefinition > FunctionExpression"]}] +// Message: Missing JSDoc comment. + +const obj = { + get aName () {}, +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkGetters":"no-setter","contexts":["Property > FunctionExpression"]}] +// Message: Missing JSDoc comment. ```` The following patterns are not considered problems: @@ -11478,6 +11504,50 @@ class Foo { } // "jsdoc/require-jsdoc": ["error"|"warn", {"checkConstructors":false,"require":{"MethodDefinition":true}}] +class Foo { + get aName () {} + set aName (val) {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkGetters":"no-setter","checkSetters":false,"contexts":["MethodDefinition > FunctionExpression"]}] + +const obj = { + get aName () {}, + set aName (val) {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkGetters":"no-setter","checkSetters":false,"contexts":["Property > FunctionExpression"]}] + +class Foo { + set aName (val) {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkSetters":false,"contexts":["MethodDefinition > FunctionExpression"]}] + +class Foo { + get aName () {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkGetters":false,"contexts":["MethodDefinition > FunctionExpression"]}] + +class Foo { + /** + * + */ + set aName (val) {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkSetters":"no-getter","contexts":["MethodDefinition > FunctionExpression"]}] + +class Foo { + /** + * + */ + get aName () {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkGetters":"no-setter","contexts":["MethodDefinition > FunctionExpression"]}] + +class Foo { + get aName () {} + set aName (val) {} +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"checkGetters":false,"checkSetters":"no-getter","contexts":["MethodDefinition > FunctionExpression"]}] + class Base { constructor() { } diff --git a/src/jsdocUtils.js b/src/jsdocUtils.js index 142e659f9..34173a6dd 100644 --- a/src/jsdocUtils.js +++ b/src/jsdocUtils.js @@ -1138,6 +1138,17 @@ const isSetter = (node) => { return node && node.parent.kind === 'set'; }; +const hasAccessorPair = (node) => { + const {type, kind: sourceKind, key: {name: sourceName}} = node; + const oppositeKind = sourceKind === 'get' ? 'set' : 'get'; + + const children = type === 'MethodDefinition' ? 'body' : 'properties'; + + return node.parent[children].some(({kind, key: {name}}) => { + return kind === oppositeKind && name === sourceName; + }); +}; + const exemptSpeciaMethods = (jsdoc, node, context, schema) => { const hasSchemaOption = (prop) => { const schemaProperties = schema[0].properties; @@ -1146,6 +1157,9 @@ const exemptSpeciaMethods = (jsdoc, node, context, schema) => { (schemaProperties[prop] && schemaProperties[prop].default); }; + const checkGetters = hasSchemaOption('checkGetters'); + const checkSetters = hasSchemaOption('checkSetters'); + return !hasSchemaOption('checkConstructors') && ( isConstructor(node) || @@ -1153,10 +1167,14 @@ const exemptSpeciaMethods = (jsdoc, node, context, schema) => { 'class', 'constructor', ])) || - !hasSchemaOption('checkGetters') && - isGetter(node) || - !hasSchemaOption('checkSetters') && - isSetter(node); + isGetter(node) && ( + !checkGetters || + checkGetters === 'no-setter' && hasAccessorPair(node.parent) + ) || + isSetter(node) && ( + !checkSetters || + checkSetters === 'no-getter' && hasAccessorPair(node.parent) + ); }; /** diff --git a/src/rules/requireJsdoc.js b/src/rules/requireJsdoc.js index cf30438e6..93cf19348 100644 --- a/src/rules/requireJsdoc.js +++ b/src/rules/requireJsdoc.js @@ -16,12 +16,28 @@ const OPTIONS_SCHEMA = { type: 'boolean', }, checkGetters: { + anyOf: [ + { + type: 'boolean', + }, + { + enum: ['no-setter'], + type: 'string', + }, + ], default: true, - type: 'boolean', }, checkSetters: { + anyOf: [ + { + type: 'boolean', + }, + { + enum: ['no-getter'], + type: 'string', + }, + ], default: true, - type: 'boolean', }, contexts: { items: { diff --git a/test/rules/assertions/requireJsdoc.js b/test/rules/assertions/requireJsdoc.js index d194c74cc..76227836a 100644 --- a/test/rules/assertions/requireJsdoc.js +++ b/test/rules/assertions/requireJsdoc.js @@ -2991,6 +2991,87 @@ function quux (foo) { } `, }, + { + code: ` + class Foo { + set aName (val) {} + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc comment.', + }, + ], + options: [ + { + checkSetters: 'no-getter', + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + output: ` + class Foo { + /** + * + */ + set aName (val) {} + } + `, + }, + { + code: ` + class Foo { + get aName () {} + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc comment.', + }, + ], + options: [ + { + checkGetters: 'no-setter', + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + output: ` + class Foo { + /** + * + */ + get aName () {} + } + `, + }, + { + code: ` + const obj = { + get aName () {}, + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc comment.', + }, + ], + options: [ + { + checkGetters: 'no-setter', + contexts: ['Property > FunctionExpression'], + }, + ], + output: ` + const obj = { + /** + * + */ + get aName () {}, + } + `, + }, ], valid: [{ code: ` @@ -4539,6 +4620,109 @@ function quux (foo) { }, ], }, + { + code: ` + class Foo { + get aName () {} + set aName (val) {} + } + `, + options: [ + { + checkGetters: 'no-setter', + checkSetters: false, + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + }, + { + code: ` + const obj = { + get aName () {}, + set aName (val) {} + } + `, + options: [ + { + checkGetters: 'no-setter', + checkSetters: false, + contexts: ['Property > FunctionExpression'], + }, + ], + }, + { + code: ` + class Foo { + set aName (val) {} + } + `, + options: [ + { + checkSetters: false, + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + }, + { + code: ` + class Foo { + get aName () {} + } + `, + options: [ + { + checkGetters: false, + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + }, + { + code: ` + class Foo { + /** + * + */ + set aName (val) {} + } + `, + options: [ + { + checkSetters: 'no-getter', + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + }, + { + code: ` + class Foo { + /** + * + */ + get aName () {} + } + `, + options: [ + { + checkGetters: 'no-setter', + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + }, + { + code: ` + class Foo { + get aName () {} + set aName (val) {} + } + `, + options: [ + { + checkGetters: false, + checkSetters: 'no-getter', + contexts: ['MethodDefinition > FunctionExpression'], + }, + ], + }, { code: ` class Base {