Skip to content

Fix: Add registeredComponentsOnly option to component-name-in-template-casing rule #714

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

Merged
merged 7 commits into from
Jan 3, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
83 changes: 16 additions & 67 deletions docs/rules/component-name-in-template-casing.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,22 @@ This rule aims to warn the tag names other than the configured casing in Vue.js
{
"vue/component-name-in-template-casing": ["error", "PascalCase" | "kebab-case", {
"registeredComponentsOnly": true,
"globalRegisteredComponents": [],
"globalRegisteredComponentPatterns": [],
"ignores": []
}]
}
```

- `"PascalCase"` (default) ... enforce tag names to pascal case. E.g. `<CoolComponent>`. This is consistent with the JSX practice.
- `"kebab-case"` ... enforce tag names to kebab case: E.g. `<cool-component>`. This is consistent with the HTML practice which is case-insensitive originally.
- `registeredComponentsOnly` ... If `true`, only registered components are checked. If `false`, check all.
- `registeredComponentsOnly` ... If `true`, only registered components (in PascalCase) are checked. If `false`, check all.
default `true`
- `globalRegisteredComponents` (`string[]`) ... (Only available when `registeredComponentsOnly` is `true`) The name of globally registered components.
- `globalRegisteredComponentPatterns` (`string[]`) ... (Only available when `registeredComponentsOnly` is `true`) The pattern of the names of globally registered components.
- `ignores` (`string[]`) ... The element names to ignore. Sets the element name to allow. For example, a custom element or a non-Vue component.
- `ignores` (`string[]`) ... The element names to ignore. Sets the element name to allow. For example, custom elements or Vue components with special name. You can set the regexp by writing it like `"/^name/"`.

### `"PascalCase", { registeredComponentsOnly: true }` (default)

<eslint-code-block fix :rules="{'vue/component-name-in-template-casing': ['error']}">

```html
```vue
<template>
<!-- ✓ GOOD -->
<CoolComponent />
Expand All @@ -54,11 +50,16 @@ This rule aims to warn the tag names other than the configured casing in Vue.js
<!-- ignore -->
<UnregisteredComponent />
<unregistered-component />

<registered-in-kebab-case />
<registeredInCamelCase />
</template>
<script>
export default {
components: {
CoolComponent
CoolComponent,
'registered-in-kebab-case': VueComponent1,
'registeredInCamelCase': VueComponent2
}
}
</script>
Expand All @@ -70,7 +71,7 @@ export default {

<eslint-code-block fix :rules="{'vue/component-name-in-template-casing': ['error', 'kebab-case']}">

```
```vue
<template>
<!-- ✓ GOOD -->
<cool-component />
Expand All @@ -95,65 +96,11 @@ export default {

</eslint-code-block>

### `"PascalCase", { globalRegisteredComponents: ["GlobalComponent"] }`

<eslint-code-block fix :rules="{'vue/component-name-in-template-casing': ['error', 'PascalCase', { globalRegisteredComponents: ['GlobalComponent'] }]}">

```html
<template>
<!-- ✓ GOOD -->
<CoolComponent />
<GlobalComponent />

<!-- ✗ BAD -->
<cool-component />
<global-component />
</template>
<script>
export default {
components: {
CoolComponent
}
}
</script>
```

</eslint-code-block>

### `"PascalCase", { globalRegisteredComponentPatterns: ["^Global"] }`

<eslint-code-block fix :rules="{'vue/component-name-in-template-casing': ['error', 'PascalCase', { globalRegisteredComponentPatterns: ['^Global'] }]}">

```html
<template>
<!-- ✓ GOOD -->
<CoolComponent />
<GlobalButton />
<GlobalCard />
<GlobalGrid />

<!-- ✗ BAD -->
<cool-component />
<global-button />
<global-card />
<global-grid />
</template>
<script>
export default {
components: {
CoolComponent
}
}
</script>
```

</eslint-code-block>

### `"PascalCase", { registeredComponentsOnly: false }`

<eslint-code-block fix :rules="{'vue/component-name-in-template-casing': ['error', 'PascalCase', { registeredComponentsOnly: false }]}">

```html
```vue
<template>
<!-- ✓ GOOD -->
<CoolComponent />
Expand All @@ -174,15 +121,17 @@ export default {

</eslint-code-block>

### `"PascalCase", { ignores: ["custom-element"], registeredComponentsOnly: false }`
### `"PascalCase", { ignores: ["/^custom-/"], registeredComponentsOnly: false }`

<eslint-code-block fix :rules="{'vue/component-name-in-template-casing': ['error', 'PascalCase', {ignores: ['custom-element'], registeredComponentsOnly: false}]}">
<eslint-code-block fix :rules="{'vue/component-name-in-template-casing': ['error', 'PascalCase', {ignores: ['/^custom-/'], registeredComponentsOnly: false}]}">

```
```vue
<template>
<!-- ✓ GOOD -->
<CoolComponent/>
<custom-element></custom-element>
<custom-button></custom-button>
<custom-input />

<!-- ✗ BAD -->
<magic-element></magic-element>
Expand Down
48 changes: 27 additions & 21 deletions lib/rules/component-name-in-template-casing.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,32 @@
const utils = require('../utils')
const casing = require('../utils/casing')

// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------

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

const RE_REGEXP_CHAR = /[\\^$.*+?()[\]{}|]/gu
Copy link
Member

Choose a reason for hiding this comment

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

What do you think about adding comment above for a reference with example string that it describes? Or even better, write unit test for each REGEX? From my experience unit tests serve the best documentation for regular expressions :)

Copy link
Member Author

Choose a reason for hiding this comment

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

@michalsnik
Thank you for review! I added test cases.

const RE_HAS_REGEXP_CHAR = new RegExp(RE_REGEXP_CHAR.source)
function escapeRegExp (string) {
return (string && RE_HAS_REGEXP_CHAR.test(string))
? string.replace(RE_REGEXP_CHAR, '\\$&')
: string
}

const RE_REGEXP_STR = /^\/(.+)\/(.*)$/u
function toRegExpList (array) {
return array.map(str => {
const parts = RE_REGEXP_STR.exec(str)
if (parts) {
return new RegExp(parts[1], parts[2])
}
return new RegExp(`^${escapeRegExp(str)}$`)
})
}

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -42,18 +65,6 @@ module.exports = {
},
registeredComponentsOnly: {
type: 'boolean'
},
globalRegisteredComponents: {
type: 'array',
items: { type: 'string' },
uniqueItems: true,
additionalItems: false
},
globalRegisteredComponentPatterns: {
type: 'array',
items: { type: 'string' },
uniqueItems: true,
additionalItems: false
}
},
additionalProperties: false
Expand All @@ -65,19 +76,19 @@ module.exports = {
const caseOption = context.options[0]
const options = context.options[1] || {}
const caseType = allowedCaseOptions.indexOf(caseOption) !== -1 ? caseOption : defaultCase
const ignores = options.ignores || []
const ignores = toRegExpList(options.ignores || [])
const registeredComponentsOnly = options.registeredComponentsOnly !== false
const registeredComponents = options.globalRegisteredComponents || []
const globalRegisteredComponentPatterns = (options.globalRegisteredComponentPatterns || []).map(s => new RegExp(s))
const tokens = context.parserServices.getTemplateBodyTokenStore && context.parserServices.getTemplateBodyTokenStore()

const registeredComponents = []

/**
* Checks whether the given node is the verification target node.
* @param {VElement} node element node
* @returns {boolean} `true` if the given node is the verification target node.
*/
function isVerifyTarget (node) {
if (ignores.indexOf(node.rawName) >= 0) {
if (ignores.some(re => re.test(node.rawName))) {
// ignore
return false
}
Expand All @@ -92,18 +103,13 @@ module.exports = {
}
return true
}

// We only verify the components registered in the component.
if (registeredComponents
.filter(name => casing.pascalCase(name) === name) // When defining a component with PascalCase, you can use either case
.some(name => node.rawName === name || casing.pascalCase(node.rawName) === name)) {
return true
}

if (globalRegisteredComponentPatterns
.some(re => node.rawName.match(re) || casing.pascalCase(node.rawName).match(re))) {
return true
}
return false
}

Expand Down
Loading