diff --git a/package-lock.json b/package-lock.json index 556ca1bb19272..dd6154b74c2de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4805,10 +4805,29 @@ "dev": true, "requires": { "babel-eslint": "^10.0.1", + "eslint-plugin-jsdoc": "^15.8.0", "eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-react": "^7.12.4", "eslint-plugin-react-hooks": "^1.6.0", + "globals": "^12.0.0", "requireindex": "^1.2.0" + }, + "dependencies": { + "globals": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.0.0.tgz", + "integrity": "sha512-c9xoi32iDwlETiyYfO0pd3M8GcEuytJinSoqq7k3fz4H8p2p31NyfKr7JVd7Y0QvmtWcWXcwqW4L33eeDYgh1A==", + "dev": true, + "requires": { + "type-fest": "^0.6.0" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } } }, "@wordpress/format-library": { @@ -8056,6 +8075,12 @@ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, + "comment-parser": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.6.1.tgz", + "integrity": "sha512-Putzd7Ilyvknmb1KxGf5el9uw0sPx9gEVnDrm8tlvXGN1i8Uaa2VBxB32hUhfzTlrEhhxNQ+pKq4ZNe8wNxjmw==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -10666,6 +10691,44 @@ "integrity": "sha512-4fxfe2RcqzU+IVNQL5n4pqibLcUhKKxihYsA510+6kC/FTdGInszDDHgO4ntBzPWu8mcHAvKJLs8o3AQw6eHTg==", "dev": true }, + "eslint-plugin-jsdoc": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.8.0.tgz", + "integrity": "sha512-J6ozWkaAgBh1eLdQE+C2wcXhoEgDmGJOSB6zMF5ktEtMBnU62xT3wfHcUacuTnv6rt+ollC0uZThaEpGA+sTNg==", + "dev": true, + "requires": { + "comment-parser": "^0.6.1", + "debug": "^4.1.1", + "flat-map-polyfill": "^0.3.8", + "jsdoctypeparser": "5.0.1", + "lodash": "^4.17.15", + "object.entries-ponyfill": "^1.0.1", + "regextras": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "eslint-plugin-jsx-a11y": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz", @@ -11527,6 +11590,12 @@ } } }, + "flat-map-polyfill": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/flat-map-polyfill/-/flat-map-polyfill-0.3.8.tgz", + "integrity": "sha512-ZfmD5MnU7GglUEhiky9C7yEPaNq1/wh36RDohe+Xr3nJVdccwHbdTkFIYvetcdsoAckUKT51fuf44g7Ni5Doyg==", + "dev": true + }, "flatted": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", @@ -15460,6 +15529,12 @@ "integrity": "sha512-wkjURqwaB1daNkDi2OYYbsLnIdC/lUM2nPXQKRs5pqEU9chDg435bjvo+LSaHotDENygHQDHe+ntUkkw2gwMtg==", "dev": true }, + "jsdoctypeparser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-5.0.1.tgz", + "integrity": "sha512-dYwcK6TKzvq+ZKtbp4sbQSW9JMo6s+4YFfUs5D/K7bZsn3s1NhEhZ+jmIPzby0HbkbECBe+hNPEa6a+E21o94w==", + "dev": true + }, "jsdom": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", @@ -18916,6 +18991,12 @@ "has": "^1.0.1" } }, + "object.entries-ponyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.entries-ponyfill/-/object.entries-ponyfill-1.0.1.tgz", + "integrity": "sha1-Kavfd8v70mVm3RqiTp2I9lQz0lY=", + "dev": true + }, "object.fromentries": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", @@ -22368,6 +22449,12 @@ "unicode-match-property-value-ecmascript": "^1.1.0" } }, + "regextras": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.6.1.tgz", + "integrity": "sha512-EzIHww9xV2Kpqx+corS/I7OBmf2rZ0pKKJPsw5Dc+l6Zq1TslDmtRIP9maVn3UH+72MIXmn8zzDgP07ihQogUA==", + "dev": true + }, "regjsgen": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 990f39fa099cb..32d6bfebb4caf 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,7 @@ ### Breaking Changes - The [`@wordpress/no-unused-vars-before-return` rule](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars-before-return.md) has been improved to exempt object destructuring only if destructuring to more than one property. +- Stricter JSDoc linting using [`eslint-plugin-jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc). ## 2.4.0 (2019-08-05) @@ -19,6 +20,7 @@ ### Improvements - The recommended `react` configuration specifies an option to [`@wordpress/no-unused-vars-before-return`](https://github.com/WordPress/gutenberg/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars-before-return.md) to exempt React hooks usage, by convention of hooks beginning with "use" prefix. +- The plugin now uses [`eslint-plugin-jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc), rather than the `valid-jsdoc` rule, for more reliable linting of JSDoc blocks. ## 2.3.0 (2019-06-12) diff --git a/packages/eslint-plugin/configs/es5.js b/packages/eslint-plugin/configs/es5.js index a13168d1223e0..c81f5c2249f9d 100644 --- a/packages/eslint-plugin/configs/es5.js +++ b/packages/eslint-plugin/configs/es5.js @@ -73,30 +73,6 @@ module.exports = { '!': true, }, } ], - 'valid-jsdoc': [ 'error', { - prefer: { - arg: 'param', - argument: 'param', - extends: 'augments', - returns: 'return', - }, - preferType: { - array: 'Array', - bool: 'boolean', - Boolean: 'boolean', - float: 'number', - Float: 'number', - int: 'number', - integer: 'number', - Integer: 'number', - Number: 'number', - object: 'Object', - String: 'string', - Void: 'void', - }, - requireParamDescription: false, - requireReturn: false, - } ], 'valid-typeof': 'error', 'vars-on-top': 'error', 'wrap-iife': 'error', diff --git a/packages/eslint-plugin/configs/jsdoc.js b/packages/eslint-plugin/configs/jsdoc.js new file mode 100644 index 0000000000000..2fda492cd445d --- /dev/null +++ b/packages/eslint-plugin/configs/jsdoc.js @@ -0,0 +1,29 @@ +const globals = require( 'globals' ); + +module.exports = { + extends: [ + 'plugin:jsdoc/recommended', + ], + settings: { + jsdoc: { + preferredTypes: { + object: 'Object', + }, + tagNamePreference: { + returns: 'return', + yields: 'yield', + }, + }, + }, + rules: { + 'jsdoc/no-undefined-types': [ 'warning', { + // Required to reference browser types because we don't have the `browser` environment enabled for the project. + // Here we filter out all browser globals that don't begin with an uppercase letter because those + // generally refer to window-level event listeners and are not a valid type to reference (e.g. `onclick`). + definedTypes: Object.keys( globals.browser ).filter( ( k ) => /^[A-Z]/.test( k ) ), + } ], + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-param-description': 'off', + 'jsdoc/require-returns': 'off', + }, +}; diff --git a/packages/eslint-plugin/configs/recommended.js b/packages/eslint-plugin/configs/recommended.js index f7c264684ecaf..96a6402237941 100644 --- a/packages/eslint-plugin/configs/recommended.js +++ b/packages/eslint-plugin/configs/recommended.js @@ -5,6 +5,7 @@ module.exports = { require.resolve( './custom.js' ), require.resolve( './react.js' ), require.resolve( './esnext.js' ), + require.resolve( './jsdoc.js' ), ], env: { node: true, diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index b8c4bc4b48512..a8139e218160e 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -25,9 +25,11 @@ "main": "index.js", "dependencies": { "babel-eslint": "^10.0.1", + "eslint-plugin-jsdoc": "^15.8.0", "eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-react": "^7.12.4", "eslint-plugin-react-hooks": "^1.6.0", + "globals": "^12.0.0", "requireindex": "^1.2.0" }, "publishConfig": {