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

⭐️New: Add vue/component-name-in-template-casing #397

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
98dbf8a
Add Vue.extend support, add missing info about Vue.mixin check in readme
michalsnik Jan 2, 2018
7c4a1d2
Docs: fixes wording in docs (#372)
samturrell Feb 1, 2018
cd22a28
Fix: fix script-indent to prevent removing <script> tag (fixes #367) …
mysticatea Feb 16, 2018
ee5cc0a
[Update] Make `vue/max-attributes-per-line` fixable (#380)
ota-meshi Feb 16, 2018
6861c81
Update: make `vue/order-in-components` fixable (#381)
ota-meshi Feb 17, 2018
2b4798b
[New] Add `vue/component-name-in-template-casing`
ota-meshi Feb 19, 2018
3f86365
[update] documents
ota-meshi Feb 19, 2018
3dd2038
[fix] require-meta-docs-url
ota-meshi Feb 19, 2018
e35ca6c
[fix] failed tests
ota-meshi Feb 19, 2018
243e61a
[fix] review contents
ota-meshi Feb 22, 2018
de29eb8
[fix] No deletes space and attributes of endTag
ota-meshi Feb 23, 2018
fea5dfc
[fix] Remove test unnecessary option
ota-meshi Feb 23, 2018
38e4849
Merge branch 'master' into add-component-name-in-template-casing
ota-meshi Feb 24, 2018
2ce184b
[fix] lint error caused by merging the master for conflict resolution
ota-meshi Feb 24, 2018
25c7e4d
Merge branch 'upstream/master' into add-component-name-in-template-ca…
ota-meshi Jul 18, 2018
54fb3fb
Add ignores option.
ota-meshi Jul 18, 2018
e8e0db0
Fixed that extra differences.
ota-meshi Jul 19, 2018
802a9a8
Merge branch 'master' into add-component-name-in-template-casing
ota-meshi Jul 27, 2018
4b300dc
update docs link
ota-meshi Jul 27, 2018
33b47d5
Merge branch 'master' into pr/397
michalsnik Jul 30, 2018
fb3d433
Update formatting
michalsnik Jul 30, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
| | Rule ID | Description |
|:---|:--------|:------------|
| :wrench: | [vue/attribute-hyphenation](./docs/rules/attribute-hyphenation.md) | enforce attribute naming style on custom components in template |
| :wrench: | [vue/component-name-in-template-casing](./docs/rules/component-name-in-template-casing.md) | enforce specific casing for the component naming style in template |
| :wrench: | [vue/html-closing-bracket-newline](./docs/rules/html-closing-bracket-newline.md) | require or disallow a line break before tag's closing brackets |
| :wrench: | [vue/html-closing-bracket-spacing](./docs/rules/html-closing-bracket-spacing.md) | require or disallow a space before tag's closing brackets |
| :wrench: | [vue/html-end-tags](./docs/rules/html-end-tags.md) | enforce end tag style |
Expand Down
74 changes: 74 additions & 0 deletions docs/rules/component-name-in-template-casing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# enforce specific casing for the component naming style in template (vue/component-name-in-template-casing)

- :gear: This rule is included in `"plugin:vue/strongly-recommended"` and `"plugin:vue/recommended"`.
- :wrench: The `--fix` option on the [command line](http://eslint.org/docs/user-guide/command-line-interface#fix) can automatically fix some of the problems reported by this rule.

Define a style for the component name in template casing for consistency purposes.

## :book: Rule Details

:+1: Examples of **correct** code for `PascalCase`:

```html
<template>
<TheComponent />
</template>
```

:-1: Examples of **incorrect** code for `PascalCase`:

```html
<template>
<the-component />
<theComponent />
<The-component />
</template>
```

:+1: Examples of **correct** code for `kebab-case`:

```html
<template>
<the-component />
</template>
```

:-1: Examples of **incorrect** code for `kebab-case`:

```html
<template>
<TheComponent />
<theComponent />
<Thecomponent />
<The-component />
</template>
```

## :wrench: Options

Default casing is set to `PascalCase`.
Copy link

@Mouvedia Mouvedia Apr 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be the default for the reasons Iv listed on #250 (comment)
Please don't merge this until that's fixed.

Copy link

@samit4me samit4me Jun 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding, we can only lint Single File Components and according to the Vue Style Guide PascalCase is strongly recommended in SFC's, so this seems like a sensible default. If you want to use kebab-case it's configurable so it can be either. +1 for this PR, really looking forward to it being merged 🎉

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this plugin uses the Style Guide as the source of truth, so If you believe kebab-case should be the default (a lot of people I work with agree) it might be more appropriate to raise a new issue over on the Style Guide repo itself, see https://github.com/vuejs/vuejs.org/blob/e93b8371d73e4467dd8152703ddf1db423f489a2/src/v2/style-guide/index.md#single-file-component-filename-casing-strongly-recommended


```json
"vue/component-name-in-template-casing": ["error",
"PascalCase|kebab-case",
{
"ignores": []
}
]
```

- `ignores` (`string[]`) ... The element name to ignore. Sets the element name to allow. For example, a custom element or a non-Vue component.


:+1: Examples of **correct** code for `{ignores: ["custom-element"]}`:

```html
<template>
<custom-element></custom-element>
<TheComponent/>
</template>
```

## Related links

- [Style guide - Component name casing in templates](https://vuejs.org/v2/style-guide/#Component-name-casing-in-templates-strongly-recommended)
1 change: 1 addition & 0 deletions lib/configs/strongly-recommended.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = {
extends: require.resolve('./essential'),
rules: {
'vue/attribute-hyphenation': 'error',
'vue/component-name-in-template-casing': 'error',
'vue/html-closing-bracket-newline': 'error',
'vue/html-closing-bracket-spacing': 'error',
'vue/html-end-tags': 'error',
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = {
'attribute-hyphenation': require('./rules/attribute-hyphenation'),
'attributes-order': require('./rules/attributes-order'),
'comment-directive': require('./rules/comment-directive'),
'component-name-in-template-casing': require('./rules/component-name-in-template-casing'),
'html-closing-bracket-newline': require('./rules/html-closing-bracket-newline'),
'html-closing-bracket-spacing': require('./rules/html-closing-bracket-spacing'),
'html-end-tags': require('./rules/html-end-tags'),
Expand Down
108 changes: 108 additions & 0 deletions lib/rules/component-name-in-template-casing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* @author Yosuke Ota
* issue https://github.com/vuejs/eslint-plugin-vue/issues/250
*/
'use strict'

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

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

const allowedCaseOptions = ['PascalCase', 'kebab-case']
const defaultCase = 'PascalCase'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
docs: {
description: 'enforce specific casing for the component naming style in template',
category: undefined, // strongly-recommended
url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v5.0.0-beta.1/docs/rules/component-name-in-template-casing.md'
},
fixable: 'code',
schema: [
{
enum: allowedCaseOptions
},
{
type: 'object',
properties: {
ignores: {
type: 'array',
items: { type: 'string' },
uniqueItems: true,
additionalItems: false
}
},
additionalProperties: false
}
]
},

create (context) {
const caseOption = context.options[0]
const options = context.options[1] || {}
const caseType = allowedCaseOptions.indexOf(caseOption) !== -1 ? caseOption : defaultCase
const ignores = options.ignores || []
const tokens = context.parserServices.getTemplateBodyTokenStore && context.parserServices.getTemplateBodyTokenStore()
const sourceCode = context.getSourceCode()

let hasInvalidEOF = false

return utils.defineTemplateBodyVisitor(context, {
'VElement' (node) {
if (hasInvalidEOF) {
return
}

if (!utils.isCustomComponent(node)) {
return
}

const name = node.rawName
if (ignores.indexOf(name) >= 0) {
return
}
const casingName = casing.getConverter(caseType)(name)
if (casingName !== name) {
const startTag = node.startTag
const open = tokens.getFirstToken(startTag)

context.report({
node: open,
loc: open.loc,
message: 'Component name "{{name}}" is not {{caseType}}.',
data: {
name,
caseType
},
fix: fixer => {
const endTag = node.endTag
if (!endTag) {
return fixer.replaceText(open, `<${casingName}`)
}
const endTagOpen = tokens.getFirstToken(endTag)
// If we can upgrade requirements to `eslint@>4.1.0`, this code can be replaced by:
// return [
// fixer.replaceText(open, `<${casingName}`),
// fixer.replaceText(endTagOpen, `</${casingName}`)
// ]
const code = `<${casingName}${sourceCode.text.slice(open.range[1], endTagOpen.range[0])}</${casingName}`
return fixer.replaceTextRange([open.range[0], endTagOpen.range[1]], code)
}
})
}
}
}, {
Program (node) {
hasInvalidEOF = utils.hasInvalidEOF(node)
}
})
}
}
Loading