From c39168280b40c392fb7c3a74ab80eeca64b7cacf Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Mon, 14 Oct 2019 22:21:31 +0800 Subject: [PATCH] feat(`check-types`, `no-undefined-types`, `valid-types`): with `settings.jsdoc.mode`, only expect types on certain tags if in `"closure"` mode --- .README/README.md | 4 +++- .README/rules/check-types.md | 2 +- .README/rules/no-undefined-types.md | 6 +++++- .README/rules/valid-types.md | 1 + README.md | 25 ++++++++++++++++++++++--- src/iterateJsdoc.js | 6 +++--- src/jsdocUtils.js | 27 ++++++++++++++++----------- src/rules/checkTypes.js | 6 +++--- src/rules/noUndefinedTypes.js | 6 +++--- src/rules/validTypes.js | 2 +- test/rules/assertions/validTypes.js | 28 ++++++++++++++++++++++++++++ 11 files changed, 86 insertions(+), 27 deletions(-) diff --git a/.README/README.md b/.README/README.md index 7ee2094dc..ba7ab29d5 100644 --- a/.README/README.md +++ b/.README/README.md @@ -92,7 +92,9 @@ You can then selectively add to or override the recommended rules. - `settings.jsdoc.mode` - Set to `jsdoc` (the default), `typescript`, or `closure`. Currently is used for checking preferred tag names and in the `check-tag-names` - rule. + rule. For type-checking rules, the setting also determines which tags will be + checked for types (Closure allows types on some tags which the others do not, + so these tags will additionally be checked in "closure" mode). ### Alias Preference diff --git a/.README/rules/check-types.md b/.README/rules/check-types.md index af785142e..6884aab9b 100644 --- a/.README/rules/check-types.md +++ b/.README/rules/check-types.md @@ -89,6 +89,6 @@ String | **string** | **string** | `("test") instanceof String` -> **`false`** |Aliases|`constructor`, `const`, `extends`, `var`, `arg`, `argument`, `prop`, `return`, `exception`, `yield`| |Closure-only|`package`, `private`, `protected`, `public`, `static`| |Options|`noDefaults`, `unifyParentAndChildTypeChecks`| -|Settings|`preferredTypes`| +|Settings|`preferredTypes`, `mode`| diff --git a/.README/rules/no-undefined-types.md b/.README/rules/no-undefined-types.md index 9504e6d6c..bc1db775a 100644 --- a/.README/rules/no-undefined-types.md +++ b/.README/rules/no-undefined-types.md @@ -13,6 +13,10 @@ the tag types in the table below: `@callback`, `@class` (or `@constructor`), `@constant` (or `@const`), `@event`, `@external` (or `@host`), `@function` (or `@func` or `@method`), `@interface`, `@member` (or `@var`), `@mixin`, `@name`, `@namespace`, `@template` (for Closure/TypeScript), `@typedef`. +The following tags will also be checked but only when the mode is `closure`: + +`@package`, `@private`, `@protected`, `@public`, `@static` + The following types are always considered defined. - `null`, `undefined`, `void`, `string`, `boolean`, `object`, `function` @@ -38,6 +42,6 @@ An option object may have the following key: |Aliases|`constructor`, `const`, `extends`, `var`, `arg`, `argument`, `prop`, `return`, `exception`, `yield`| |Closure-only|`package`, `private`, `protected`, `public`, `static`| |Options|`definedTypes`| -|Settings|`preferredTypes`| +|Settings|`preferredTypes`, `mode`| diff --git a/.README/rules/valid-types.md b/.README/rules/valid-types.md index 882b44b38..f20a4817c 100644 --- a/.README/rules/valid-types.md +++ b/.README/rules/valid-types.md @@ -54,5 +54,6 @@ Also impacts behaviors on namepath (or event)-defining and pointing tags: |Aliases|`extends`, `constructor`, `const`, `host`, `emits`, `func`, `method`, `var`, `arg`, `argument`, `prop`, `return`, `exception`, `yield`| |Closure-only|For type only: `package`, `private`, `protected`, `public`, `static`| |Options|`allowEmptyNamepaths`, `checkSeesForNamepaths`| +|Settings|`mode`| diff --git a/README.md b/README.md index 5defb6442..b4e94cdc3 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,9 @@ You can then selectively add to or override the recommended rules. - `settings.jsdoc.mode` - Set to `jsdoc` (the default), `typescript`, or `closure`. Currently is used for checking preferred tag names and in the `check-tag-names` - rule. + rule. For type-checking rules, the setting also determines which tags will be + checked for types (Closure allows types on some tags which the others do not, + so these tags will additionally be checked in "closure" mode). ### Alias Preference @@ -2197,7 +2199,7 @@ String | **string** | **string** | `("test") instanceof String` -> **`false`** |Aliases|`constructor`, `const`, `extends`, `var`, `arg`, `argument`, `prop`, `return`, `exception`, `yield`| |Closure-only|`package`, `private`, `protected`, `public`, `static`| |Options|`noDefaults`, `unifyParentAndChildTypeChecks`| -|Settings|`preferredTypes`| +|Settings|`preferredTypes`, `mode`| The following patterns are considered problems: @@ -3896,6 +3898,10 @@ the tag types in the table below: `@callback`, `@class` (or `@constructor`), `@constant` (or `@const`), `@event`, `@external` (or `@host`), `@function` (or `@func` or `@method`), `@interface`, `@member` (or `@var`), `@mixin`, `@name`, `@namespace`, `@template` (for Closure/TypeScript), `@typedef`. +The following tags will also be checked but only when the mode is `closure`: + +`@package`, `@private`, `@protected`, `@public`, `@static` + The following types are always considered defined. - `null`, `undefined`, `void`, `string`, `boolean`, `object`, `function` @@ -3922,7 +3928,7 @@ An option object may have the following key: |Aliases|`constructor`, `const`, `extends`, `var`, `arg`, `argument`, `prop`, `return`, `exception`, `yield`| |Closure-only|`package`, `private`, `protected`, `public`, `static`| |Options|`definedTypes`| -|Settings|`preferredTypes`| +|Settings|`preferredTypes`, `mode`| The following patterns are considered problems: @@ -8039,6 +8045,7 @@ Also impacts behaviors on namepath (or event)-defining and pointing tags: |Aliases|`extends`, `constructor`, `const`, `host`, `emits`, `func`, `method`, `var`, `arg`, `argument`, `prop`, `return`, `exception`, `yield`| |Closure-only|For type only: `package`, `private`, `protected`, `public`, `static`| |Options|`allowEmptyNamepaths`, `checkSeesForNamepaths`| +|Settings|`mode`| The following patterns are considered problems: @@ -8171,6 +8178,13 @@ function quux() { */ function quux (foo, bar, baz) {} // Message: Syntax error in type: bar|foo< + +/** + * @private {BadTypeChecked<} + */ +function quux () {} +// Settings: {"jsdoc":{"mode":"closure"}} +// Message: Syntax error in type: BadTypeChecked< ```` The following patterns are not considered problems: @@ -8317,6 +8331,11 @@ let UserDefinedGCCType; * @modifies {foo|bar} */ function quux (foo, bar, baz) {} + +/** + * @private {BadTypeNotCheckedInJsdoc<} + */ +function quux () {} ```` diff --git a/src/iterateJsdoc.js b/src/iterateJsdoc.js index e203e76fe..93aeca22c 100644 --- a/src/iterateJsdoc.js +++ b/src/iterateJsdoc.js @@ -200,7 +200,7 @@ const getUtils = ( }; utils.tagMightHaveEitherTypeOrNamepath = (tagName) => { - return jsdocUtils.tagMightHaveEitherTypeOrNamepath(tagName); + return jsdocUtils.tagMightHaveEitherTypeOrNamepath(mode, tagName); }; utils.tagMustHaveNamepath = (tagName) => { @@ -215,8 +215,8 @@ const getUtils = ( return jsdocUtils.tagMustHaveType(tagName); }; - utils.tagMightHaveType = (tagName) => { - return jsdocUtils.tagMightHaveType(tagName); + utils.tagMightHaveAType = (tagName) => { + return jsdocUtils.tagMightHaveAType(mode, tagName); }; utils.isNamepathDefiningTag = (tagName) => { diff --git a/src/jsdocUtils.js b/src/jsdocUtils.js index 766924d1b..ca9bcc1e2 100644 --- a/src/jsdocUtils.js +++ b/src/jsdocUtils.js @@ -219,7 +219,15 @@ const tagsWithOptionalType = [ 'throws', 'exception', 'yields', 'yield', - // Todo: Omit these GCC specific items when in non-GCC mode after landing https://github.com/gajus/eslint-plugin-jsdoc/issues/356 + // Has no documentation, but test example has curly brackets, and + // "name" would be suggested rather than "namepath" based on example; not + // sure if name is required + 'modifies', +]; + +const tagsWithOptionalTypeClosure = [ + ...tagsWithOptionalType, + // Shows the signature with curly brackets but not in the example // "typeExpression" 'package', @@ -229,11 +237,6 @@ const tagsWithOptionalType = [ // These do not show a signature nor show curly brackets in the example 'public', 'static', - - // Has no documentation, but test example has curly brackets, and - // "name" would be suggested rather than "namepath" based on example; not - // sure if name is required - 'modifies', ]; // None of these show as having curly brackets for their name/namepath @@ -327,8 +330,10 @@ const isNamepathDefiningTag = (tagName) => { return namepathDefiningTags.includes(tagName); }; -const tagMightHaveType = (tag) => { - return tagsWithMandatoryType.includes(tag) || tagsWithOptionalType.includes(tag); +const tagMightHaveAType = (mode, tag) => { + return tagsWithMandatoryType.includes(tag) || (mode === 'closure' ? + tagsWithOptionalTypeClosure.includes(tag) : + tagsWithOptionalType.includes(tag)); }; const tagMustHaveType = (tag) => { @@ -343,8 +348,8 @@ const tagMustHaveNamepath = (tag) => { return tagsWithMandatoryNamepath.includes(tag); }; -const tagMightHaveEitherTypeOrNamepath = (tag) => { - return tagMightHaveType(tag) || tagMightHaveNamepath(tag); +const tagMightHaveEitherTypeOrNamepath = (mode, tag) => { + return tagMightHaveAType(mode, tag) || tagMightHaveNamepath(tag); }; const tagMustHaveEitherTypeOrNamepath = (tag) => { @@ -535,9 +540,9 @@ export default { isNamepathDefiningTag, isValidTag, parseClosureTemplateTag, + tagMightHaveAType, tagMightHaveEitherTypeOrNamepath, tagMightHaveNamepath, - tagMightHaveType, tagMustHaveEitherTypeOrNamepath, tagMustHaveNamepath, tagMustHaveType, diff --git a/src/rules/checkTypes.js b/src/rules/checkTypes.js index 6756fb7f2..ca1f70a80 100644 --- a/src/rules/checkTypes.js +++ b/src/rules/checkTypes.js @@ -25,8 +25,8 @@ export default iterateJsdoc(({ settings, context, }) => { - const jsdocTags = utils.filterTags((tag) => { - return utils.tagMightHaveType(tag.tag); + const jsdocTagsWithPossibleType = utils.filterTags((tag) => { + return utils.tagMightHaveAType(tag.tag); }); const {preferredTypes} = settings; @@ -34,7 +34,7 @@ export default iterateJsdoc(({ const noDefaults = _.get(optionObj, 'noDefaults'); const unifyParentAndChildTypeChecks = _.get(optionObj, 'unifyParentAndChildTypeChecks'); - jsdocTags.forEach((jsdocTag) => { + jsdocTagsWithPossibleType.forEach((jsdocTag) => { const invalidTypes = []; let typeAst; diff --git a/src/rules/noUndefinedTypes.js b/src/rules/noUndefinedTypes.js index fa26817ae..e40a66e6d 100644 --- a/src/rules/noUndefinedTypes.js +++ b/src/rules/noUndefinedTypes.js @@ -105,11 +105,11 @@ export default iterateJsdoc(({ .concat(definedPreferredTypes) .concat(closureGenericTypes); - const jsdocTags = utils.filterTags((tag) => { - return utils.tagMightHaveType(tag.tag); + const jsdocTagsWithPossibleType = utils.filterTags((tag) => { + return utils.tagMightHaveAType(tag.tag); }); - jsdocTags.forEach((tag) => { + jsdocTagsWithPossibleType.forEach((tag) => { let parsedType; try { diff --git a/src/rules/validTypes.js b/src/rules/validTypes.js index 0ddf21bd9..30aa50a48 100644 --- a/src/rules/validTypes.js +++ b/src/rules/validTypes.js @@ -73,7 +73,7 @@ export default iterateJsdoc(({ return true; }; - const hasType = utils.tagMightHaveType(tag.tag) && Boolean(tag.type); + const hasType = utils.tagMightHaveAType(tag.tag) && Boolean(tag.type); const mustHaveType = utils.tagMustHaveType(tag.tag); const hasNamePath = utils.tagMightHaveNamepath(tag.tag) && Boolean(tag.name) && !(tag.tag === 'see' && !checkSeesForNamepaths); diff --git a/test/rules/assertions/validTypes.js b/test/rules/assertions/validTypes.js index d7256b7a1..ebadca7ed 100644 --- a/test/rules/assertions/validTypes.js +++ b/test/rules/assertions/validTypes.js @@ -267,6 +267,25 @@ export default { }, ], }, + { + code: ` + /** + * @private {BadTypeChecked<} + */ + function quux () {} + + `, + errors: [ + { + message: 'Syntax error in type: BadTypeChecked<', + }, + ], + settings: { + jsdoc: { + mode: 'closure', + }, + }, + }, ], valid: [ { @@ -481,5 +500,14 @@ export default { function quux (foo, bar, baz) {} `, }, + { + code: ` + /** + * @private {BadTypeNotCheckedInJsdoc<} + */ + function quux () {} + + `, + }, ], };