Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new vue/require-prop-comment rule #2019

Merged
merged 28 commits into from Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
641a483
require-prop-comment
czb3279338858 Sep 28, 2022
a6892f7
Merge branch 'master' of https://github.com/czb3279338858/eslint-plug…
czb3279338858 Oct 8, 2022
3e8d0e1
add type arg
czb3279338858 Oct 19, 2022
f271f48
add jsdoc type
czb3279338858 Oct 20, 2022
0fbb5f8
Merge branch 'master' of https://github.com/czb3279338858/eslint-plug…
czb3279338858 Oct 20, 2022
07ea38a
edit rule
czb3279338858 Oct 20, 2022
3ec9ba0
npm run update运行结果
czb3279338858 Oct 20, 2022
763fa82
Merge branch 'master' of https://github.com/czb3279338858/eslint-plug…
czb3279338858 Oct 25, 2022
1abad76
npm run update edit
czb3279338858 Oct 25, 2022
4b58d8b
Modify according to the requirements during consolidation
czb3279338858 Oct 25, 2022
a695a74
edit test
czb3279338858 Oct 25, 2022
9545392
delete only one check
czb3279338858 Oct 25, 2022
c4dd9f6
delete template
czb3279338858 Oct 25, 2022
2549e6b
edit md
czb3279338858 Oct 25, 2022
9acb7ab
Merge branch 'master' into master
FloEdelmann Oct 25, 2022
89b4b15
Lint
FloEdelmann Oct 27, 2022
7c08d5d
Improve docs
FloEdelmann Oct 27, 2022
57d9c5f
Only check last preceding comment
FloEdelmann Oct 27, 2022
d304e62
Use message IDs
FloEdelmann Oct 27, 2022
a2d8144
Rename unlimited → any
FloEdelmann Oct 27, 2022
e8070ac
Fix docs
FloEdelmann Oct 27, 2022
4063129
edit rules
czb3279338858 Oct 29, 2022
5a517aa
edit schema type
czb3279338858 Oct 31, 2022
03f33ff
Merge remote-tracking branch 'upstream/master'
czb3279338858 Oct 31, 2022
310fd26
update readme.md
czb3279338858 Oct 31, 2022
b4b7e6a
add rules
czb3279338858 Oct 31, 2022
1c0bd96
add rules
czb3279338858 Oct 31, 2022
0d54c19
Merge branch 'master' of https://github.com/czb3279338858/eslint-plug…
czb3279338858 Nov 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/rules/README.md
Expand Up @@ -260,6 +260,7 @@ For example:
| [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | :bulb: | :hammer: |
| [vue/require-expose](./require-expose.md) | require declare public properties using `expose` | :bulb: | :hammer: |
| [vue/require-name-property](./require-name-property.md) | require a name property in Vue components | | :hammer: |
| [vue/require-prop-comment](./require-prop-comment.md) | require props to have a comment | | :hammer: |
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: | :lipstick: |
| [vue/sort-keys](./sort-keys.md) | enforce sort-keys in a manner that is compatible with order-in-components | | :hammer: |
| [vue/static-class-names-order](./static-class-names-order.md) | enforce static class names order | :wrench: | :hammer: |
Expand Down
144 changes: 144 additions & 0 deletions docs/rules/require-prop-comment.md
@@ -0,0 +1,144 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/require-prop-comment
description: require props to have a comment
---
# vue/require-prop-comment

> require props to have a comment

- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>

## :book: Rule Details

This rule enforces that every prop has a comment that documents it.

<eslint-code-block :rules="{'vue/require-prop-comment': ['error']}">

```vue
<script>
export default defineComponent({
props: {
// ✓ GOOD
czb3279338858 marked this conversation as resolved.
Show resolved Hide resolved

/** JSDoc comment */
a: Number,

// ✗ BAD

// line comment
b: Number,

/* block comment */
c: Number,

d: Number,
}
})
</script>
```

</eslint-code-block>

## :wrench: Options

```json
{
"vue/require-prop-comment": ["error", {
"type": "JSDoc"
}]
}
```

- `type` ... Type of comment. Default is `"JSDoc"`
- `"JSDoc"` ... Only JSDoc comment are allowed.
- `"line"` ... Only line comment are allowed.
- `"block"` ... Only block comment are allowed.
- `"any"` ... All comment types are allowed.

### `"type": "block"`

<eslint-code-block :rules="{'vue/require-prop-comment': ['error', {type: 'block'}]}">

```vue
<script setup>
// ✓ GOOD
const goodProps = defineProps({
/* block comment */
a: Number,
})

// ✗ BAD
const badProps = defineProps({
/** JSDoc comment */
b: Number,

// line comment
c: Number,

d: Number,
})
</script>
```

</eslint-code-block>

### `"type": "line"`

<eslint-code-block :rules="{'vue/require-prop-comment': ['error', {type: 'line'}]}">

```vue
<script setup>
// ✓ GOOD
const goodProps = defineProps({
// line comment
a: Number,
})

// ✗ BAD
const badProps = defineProps({
/** JSDoc comment */
b: Number,

/* block comment */
c: Number,

d: Number,
})
</script>
```

</eslint-code-block>

### `"type": "any"`

<eslint-code-block :rules="{'vue/require-prop-comment': ['error', {type: 'any'}]}">

```vue
<script setup>
// ✓ GOOD
const goodProps = defineProps({
/** JSDoc comment */
a: Number,

/* block comment */
b: Number,

// line comment
c: Number,
})

// ✗ BAD
const badProps = defineProps({
d: Number,
})
</script>
```

</eslint-code-block>

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-prop-comment.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-prop-comment.js)
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -176,6 +176,7 @@ module.exports = {
'require-explicit-emits': require('./rules/require-explicit-emits'),
'require-expose': require('./rules/require-expose'),
'require-name-property': require('./rules/require-name-property'),
'require-prop-comment': require('./rules/require-prop-comment'),
'require-prop-type-constructor': require('./rules/require-prop-type-constructor'),
'require-prop-types': require('./rules/require-prop-types'),
'require-render-return': require('./rules/require-render-return'),
Expand Down
123 changes: 123 additions & 0 deletions lib/rules/require-prop-comment.js
@@ -0,0 +1,123 @@
/**
* @author CZB
* See LICENSE file in root directory for full license.
*/
'use strict'

const utils = require('../utils')

module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'require props to have a comment',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/require-prop-comment.html'
},
fixable: null,
schema: [
{
type: 'object',
properties: {
type: { enum: ['JSDoc', 'line', 'block', 'any'] }
},
additionalProperties: false
}
],
messages: {
requireAnyComment: 'The "{{name}}" property should have a comment.',
requireLineComment: 'The "{{name}}" property should have a line comment.',
requireBlockComment:
'The "{{name}}" property should have a block comment.',
requireJSDocComment:
'The "{{name}}" property should have a JSDoc comment.'
}
},
/** @param {RuleContext} context */
create(context) {
/** @type {{type?: "JSDoc" | "line" | "block" | "any"}|undefined} */
const schema = context.options[0]
const type = (schema && schema.type) || 'JSDoc'

const sourceCode = context.getSourceCode()

/** @param {Comment | undefined} comment */
const verifyBlock = (comment) =>
comment && comment.type === 'Block' && comment.value.charAt(0) !== '*'
? undefined
: 'requireBlockComment'

/** @param {Comment | undefined} comment */
const verifyLine = (comment) =>
comment && comment.type === 'Line' ? undefined : 'requireLineComment'

/** @param {Comment | undefined} comment */
const verifyAny = (comment) => (comment ? undefined : 'requireAnyComment')

/** @param {Comment | undefined} comment */
const verifyJSDoc = (comment) =>
comment && comment.type === 'Block' && comment.value.charAt(0) === '*'
? undefined
: 'requireJSDocComment'

/**
* @param {import('../utils').ComponentProp[]} props
*/
function verifyProps(props) {
for (const prop of props) {
if (!prop.propName) {
continue
}

const precedingComments = sourceCode.getCommentsBefore(prop.node)
const lastPrecedingComment =
precedingComments.length > 0
? precedingComments[precedingComments.length - 1]
: undefined

/** @type {string|undefined} */
let messageId

switch (type) {
case 'block':
messageId = verifyBlock(lastPrecedingComment)
break
case 'line':
messageId = verifyLine(lastPrecedingComment)
break
case 'any':
messageId = verifyAny(lastPrecedingComment)
break
default:
messageId = verifyJSDoc(lastPrecedingComment)
break
}

if (!messageId) {
continue
}

context.report({
node: prop.node,
messageId,
data: {
name: prop.propName
}
})
}
}

return utils.compositingVisitors(
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(_node, props) {
verifyProps(props)
}
}),
utils.defineVueVisitor(context, {
onVueObjectEnter(node) {
verifyProps(utils.getComponentPropsFromOptions(node))
}
})
)
}
}