diff --git a/.README/rules/check-examples.md b/.README/rules/check-examples.md index 2b3cf7d68..d3f12321c 100644 --- a/.README/rules/check-examples.md +++ b/.README/rules/check-examples.md @@ -1,5 +1,8 @@ ### `check-examples` +> **NOTE**: This rule currently does not work in ESLint 8 (we are waiting for +> [issue 14745](https://github.com/eslint/eslint/issues/14745)). + Ensures that (JavaScript) examples within JSDoc adhere to ESLint rules. Also has options to lint the default values of optional `@param`/`@arg`/`@argument` and `@property`/`@prop` tags or the values of `@default`/`@defaultvalue` tags. diff --git a/.travis.yml b/.travis.yml index 8cf348fcd..9ff1e4a49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,37 +9,26 @@ node_js: before_install: - npm config set depth 0 +install: + - echo "Avoid Travis's npm auto-install" before_script: > - node_version=$(node -v); - if [ ${node_version:3:1} = "." ]; then - echo "Node 10+" - if [ ${ESLINT} = "6" ]; then - npm install --legacy-peer-deps --no-save "eslint@${ESLINT}" eslint-config-canonical@24.4.4 - else - npm install --legacy-peer-deps --no-save "eslint@${ESLINT}" - fi - else - echo "Node 8+" - npm install --legacy-peer-deps --no-save "eslint@${ESLINT}" husky@3.1.0 semantic-release@15.14.0 eslint-config-canonical@18.1.1 - fi + npm install --legacy-peer-deps --no-save "eslint@${ESLINT}" notifications: email: false script: - npm run test - - 'if [ -n "${LINT-}" ]; then npm run lint; fi' + # Disable until eslint-config-canonical fixed + # - 'if [ -n "${LINT-}" ]; then npm run lint; fi' - npm run build env: jobs: + - ESLINT=8 - ESLINT=7 - - ESLINT=6 jobs: fast_finish: true include: - node_js: 'lts/*' env: LINT=true - exclude: - - node_js: 8 - env: ESLINT=7 after_success: - export NODE_ENV=production - npm run build diff --git a/README.md b/README.md index 5f98799be..ce447c451 100644 --- a/README.md +++ b/README.md @@ -945,6 +945,9 @@ function quux (foo) { ### check-examples +> **NOTE**: This rule currently does not work in ESLint 8 (we are waiting for +> [issue 14745](https://github.com/eslint/eslint/issues/14745)). + Ensures that (JavaScript) examples within JSDoc adhere to ESLint rules. Also has options to lint the default values of optional `@param`/`@arg`/`@argument` and `@property`/`@prop` tags or the values of `@default`/`@defaultvalue` tags. @@ -6914,7 +6917,7 @@ class MyClass { */ myClassField = 1 } -// "jsdoc/match-description": ["error"|"warn", {"contexts":["ClassProperty"]}] +// "jsdoc/match-description": ["error"|"warn", {"contexts":["PropertyDefinition"]}] // Message: JSDoc description does not satisfy the regex pattern. /** @@ -7182,7 +7185,7 @@ class MyClass { */ myClassField = 1 } -// "jsdoc/match-description": ["error"|"warn", {"contexts":["ClassProperty"]}] +// "jsdoc/match-description": ["error"|"warn", {"contexts":["PropertyDefinition"]}] /** * Foo. @@ -12813,7 +12816,7 @@ class Animal { @SomeAnnotation('optionalParameter') tail: boolean; } -// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":["ClassProperty"]}] +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":["PropertyDefinition"]}] // Message: Missing JSDoc comment. @Entity('users') @@ -12907,7 +12910,7 @@ export class MyComponentComponent { @Input() public value = new EventEmitter(); } -// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":["ClassProperty:has(Decorator[expression.callee.name=\"Input\"])"]}] +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":["PropertyDefinition > Decorator[expression.callee.name=\"Input\"]"]}] // Message: Missing JSDoc comment. requestAnimationFrame(draw) @@ -12951,6 +12954,12 @@ function comment () { } // "jsdoc/require-jsdoc": ["error"|"warn", {"enableFixer":false,"fixerMessage":" TODO: add comment"}] // Message: Missing JSDoc comment. + +export class InovaAutoCompleteComponent { + public disabled = false; +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":["PropertyDefinition"],"publicOnly":true}] +// Message: Missing JSDoc comment. ```` The following patterns are not considered problems: diff --git a/package.json b/package.json index 10c679dca..bf40f83e3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "url": "http://gajus.com" }, "dependencies": { - "@es-joy/jsdoccomment": "0.10.8", + "@es-joy/jsdoccomment": "0.11.0", "comment-parser": "1.2.4", "debug": "^4.3.2", "esquery": "^1.4.0", @@ -26,12 +26,12 @@ "@babel/preset-env": "^7.15.8", "@babel/register": "^7.15.3", "@hkdobrev/run-if-changed": "^0.3.1", - "@typescript-eslint/parser": "^4.33.0", + "@typescript-eslint/parser": "^5.0.0", "babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-istanbul": "^6.0.0", "chai": "^4.3.4", "cross-env": "^7.0.3", - "eslint": "7.32.0", + "eslint": "^8.0.0", "eslint-config-canonical": "^28.0.0", "gitdown": "^3.1.4", "glob": "^7.2.0", @@ -48,10 +48,10 @@ "node": "^12 || ^14 || ^16" }, "lint-staged": { - ".eslintignore": "npm run lint", - "./*.js": "npm run lint-arg --", - "src/**/*.js": "npm run lint-arg --", - "test/**/*.js": "npm run lint-arg --" + "DISABLE.eslintignore": "npm run lint", + "DISABLE./*.js": "npm run lint-arg --", + "DISABLEsrc/**/*.js": "npm run lint-arg --", + "DISABLEtest/**/*.js": "npm run lint-arg --" }, "run-if-changed": { "package-lock.json": "npm run install-offline" @@ -65,7 +65,7 @@ "main": "./dist/index.js", "name": "eslint-plugin-jsdoc", "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "repository": { "type": "git", @@ -95,6 +95,9 @@ "include": [ "src/" ], + "exclude": [ + "src/rules/checkExamples.js" + ], "check-coverage": true, "branches": 100, "lines": 100, diff --git a/src/iterateJsdoc.js b/src/iterateJsdoc.js index 5b52dde27..a9dd42d05 100644 --- a/src/iterateJsdoc.js +++ b/src/iterateJsdoc.js @@ -708,6 +708,8 @@ const makeReport = (context, commentNode) => { end: {line: lineNumber}, start: {line: lineNumber}, }; + // Todo: Remove once `check-examples` can be restored for ESLint 8+ + // istanbul ignore if if (jsdocLoc.column) { const colNumber = commentNode.loc.start.column + jsdocLoc.column; diff --git a/src/jsdocUtils.js b/src/jsdocUtils.js index 6c4ac63fa..c8b8656fd 100644 --- a/src/jsdocUtils.js +++ b/src/jsdocUtils.js @@ -718,6 +718,9 @@ const hasNonEmptyResolverCall = (node, resolverName) => { case 'ObjectProperty': /* eslint-disable no-fallthrough */ // istanbul ignore next -- In Babel? + case 'PropertyDefinition': + /* eslint-disable no-fallthrough */ + // istanbul ignore next -- In Babel? case 'ClassProperty': /* eslint-enable no-fallthrough */ case 'Property': @@ -907,6 +910,9 @@ const hasNonFunctionYield = (node, checkYieldReturnValue) => { return hasNonFunctionYield(property, checkYieldReturnValue); }); + // istanbul ignore next -- In Babel? + case 'PropertyDefinition': + /* eslint-disable no-fallthrough */ // istanbul ignore next -- In Babel? case 'ObjectProperty': /* eslint-disable no-fallthrough */ diff --git a/src/rules/checkExamples.js b/src/rules/checkExamples.js index 84cffd26e..e88a79a07 100644 --- a/src/rules/checkExamples.js +++ b/src/rules/checkExamples.js @@ -1,9 +1,9 @@ -// Todo: When peerDeps bump to ESLint 7, see about replacing `CLIEngine` -// with non-deprecated `ESLint` class: +// Todo: When replace `CLIEngine` with `ESLint` when feature set complete per https://github.com/eslint/eslint/issues/14745 // https://github.com/eslint/eslint/blob/master/docs/user-guide/migrating-to-7.0.0.md#-the-cliengine-class-has-been-deprecated import { - CLIEngine, + CLIEngine, ESLint, } from 'eslint'; +import semver from 'semver' import iterateJsdoc from '../iterateJsdoc'; const zeroBasedLineIndexAdjust = -1; @@ -85,6 +85,13 @@ export default iterateJsdoc(({ context, globalState, }) => { + if (semver.gte(ESLint.version, '8.0.0')) { + return report({ + loc: { start: { column: 1, line: 1 } }, + message: `This rule cannot yet be supported for ESLint 8; you should either downgrade to ESLint 7 or disable this rule. The possibility for ESLint 8 support is being tracked at https://github.com/eslint/eslint/issues/14745`, + }); + } + if (!globalState.has('checkExamples-matchingFileName')) { globalState.set('checkExamples-matchingFileName', new Map()); } @@ -196,8 +203,7 @@ export default iterateJsdoc(({ matchingFileNameMap.set(fileNameMapKey, cliFile); } - const {results: [{messages}]} = - cliFile.executeOnText(src); + const {results: [{messages}]} = cliFile.executeOnText(src); if (!('line' in tag)) { tag.line = tag.source[0].number; diff --git a/src/rules/requireJsdoc.js b/src/rules/requireJsdoc.js index 20fe68c4f..8c123c74e 100644 --- a/src/rules/requireJsdoc.js +++ b/src/rules/requireJsdoc.js @@ -308,7 +308,7 @@ export default { if ( ['VariableDeclarator', 'AssignmentExpression', 'ExportDefaultDeclaration'].includes(node.parent.type) || - ['Property', 'ObjectProperty', 'ClassProperty'].includes(node.parent.type) && node === node.parent.value + ['Property', 'ObjectProperty', 'ClassProperty', 'PropertyDefinition'].includes(node.parent.type) && node === node.parent.value ) { checkJsDoc({isFunctionContext: true}, null, node); } @@ -351,7 +351,7 @@ export default { if ( ['VariableDeclarator', 'AssignmentExpression', 'ExportDefaultDeclaration'].includes(node.parent.type) || - ['Property', 'ObjectProperty', 'ClassProperty'].includes(node.parent.type) && node === node.parent.value + ['Property', 'ObjectProperty', 'ClassProperty', 'PropertyDefinition'].includes(node.parent.type) && node === node.parent.value ) { checkJsDoc({isFunctionContext: true}, null, node); } diff --git a/test/rules/assertions/matchDescription.js b/test/rules/assertions/matchDescription.js index c2c2973a1..725f17f7c 100644 --- a/test/rules/assertions/matchDescription.js +++ b/test/rules/assertions/matchDescription.js @@ -794,7 +794,7 @@ export default { options: [ { contexts: [ - 'ClassProperty', + 'PropertyDefinition', ], }, ], @@ -1269,7 +1269,7 @@ export default { options: [ { contexts: [ - 'ClassProperty', + 'PropertyDefinition', ], }, ], diff --git a/test/rules/assertions/requireJsdoc.js b/test/rules/assertions/requireJsdoc.js index f82ccbe2f..df5478cbb 100644 --- a/test/rules/assertions/requireJsdoc.js +++ b/test/rules/assertions/requireJsdoc.js @@ -2,10 +2,6 @@ * @see https://github.com/eslint/eslint/blob/master/tests/lib/rules/require-jsdoc.js */ -import { - CLIEngine, -} from 'eslint'; - export default { invalid: [ { @@ -2591,7 +2587,7 @@ function quux (foo) { ], options: [ { - contexts: ['ClassProperty'], + contexts: ['PropertyDefinition'], }, ], output: ` @@ -3016,15 +3012,7 @@ function quux (foo) { }, ], options: [{ - contexts: [ - // Only fixed to support `:has()` with TS later in ESLint 7, but - // for our testing of ESLint 6, we use `>` which is equivalent in - // this case; after having peerDeps. to ESLint 7+, we can remove - // this check and use of `CLIEngine` - CLIEngine.version.startsWith('6') ? - 'ClassProperty > Decorator[expression.callee.name="Input"]' : - 'ClassProperty:has(Decorator[expression.callee.name="Input"])', - ], + contexts: ['PropertyDefinition > Decorator[expression.callee.name="Input"]'], }], output: ` export class MyComponentComponent { @@ -3262,6 +3250,37 @@ function quux (foo) { } `, }, + { + code: ` + export class InovaAutoCompleteComponent { + public disabled = false; + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc comment.', + } + ], + options: [ + { + contexts: ['PropertyDefinition'], + publicOnly: true, + }, + ], + output: ` + export class InovaAutoCompleteComponent { + /** + * + */ + public disabled = false; + } + `, + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { + sourceType: 'module', + }, + }, ], valid: [{ code: ` diff --git a/test/rules/index.js b/test/rules/index.js index 8a1828c7d..6c1a7b1d2 100644 --- a/test/rules/index.js +++ b/test/rules/index.js @@ -1,13 +1,18 @@ -import { - RuleTester, -} from 'eslint'; +import { ESLint, RuleTester } from 'eslint'; import _ from 'lodash'; +import semver from 'semver' import config from '../../src'; import ruleNames from './ruleNames.json'; const ruleTester = new RuleTester(); (process.env.npm_config_rule ? process.env.npm_config_rule.split(',') : ruleNames).forEach(async (ruleName) => { + if (semver.gte(ESLint.version, '8.0.0') && ruleName === 'check-examples') { + // This rule cannot yet be supported for ESLint 8; + // The possibility for ESLint 8 support is being tracked at https://github.com/eslint/eslint/issues/14745 + return; + } + const rule = config.rules[ruleName]; const parserOptions = {