Skip to content

Commit 2d7739b

Browse files
authored
Add @intlify/vue-i18n/no-i18n-t-path-prop rule (#167)
1 parent 062230f commit 2d7739b

File tree

5 files changed

+215
-0
lines changed

5 files changed

+215
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
| [@intlify/vue-i18n/<wbr>no-deprecated-i18n-component](./no-deprecated-i18n-component.html) | disallow using deprecated `<i18n>` components (in Vue I18n 9.0.0+) | :black_nib: |
1212
| [@intlify/vue-i18n/<wbr>no-deprecated-i18n-place-attr](./no-deprecated-i18n-place-attr.html) | disallow using deprecated `place` attribute (Removed in Vue I18n 9.0.0+) | |
1313
| [@intlify/vue-i18n/<wbr>no-html-messages](./no-html-messages.html) | disallow use HTML localization messages | :star: |
14+
| [@intlify/vue-i18n/<wbr>no-i18n-t-path-prop](./no-i18n-t-path-prop.html) | disallow using `path` prop with `<i18n-t>` | :black_nib: |
1415
| [@intlify/vue-i18n/<wbr>no-missing-keys](./no-missing-keys.html) | disallow missing locale message key at localization methods | :star: |
1516
| [@intlify/vue-i18n/<wbr>no-raw-text](./no-raw-text.html) | disallow to string literal in template or JSX | :star: |
1617
| [@intlify/vue-i18n/<wbr>no-v-html](./no-v-html.html) | disallow use of localization methods on v-html to prevent XSS attack | :star: |

docs/rules/no-i18n-t-path-prop.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: '@intlify/vue-i18n/no-i18n-t-path-prop'
3+
description: disallow using `path` prop with `<i18n-t>`
4+
---
5+
6+
# @intlify/vue-i18n/no-i18n-t-path-prop
7+
8+
> disallow using `path` prop with `<i18n-t>`
9+
10+
- :black_nib:️ 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.
11+
12+
You cannot use `path` prop with `<i18n-t>` component. Perhaps it's an old habit mistake.
13+
14+
## :book: Rule Details
15+
16+
This rule reports use of `path` prop with `<i18n-t>` component.
17+
18+
:-1: Examples of **incorrect** code for this rule:
19+
20+
<eslint-code-block fix>
21+
22+
<!-- eslint-skip -->
23+
24+
```vue
25+
<script>
26+
/* eslint @intlify/vue-i18n/no-i18n-t-path-prop: 'error' */
27+
</script>
28+
<template>
29+
<div class="app">
30+
<!-- ✗ BAD -->
31+
<i18n-t path="message.greeting" />
32+
</div>
33+
</template>
34+
```
35+
36+
</eslint-code-block>
37+
38+
:+1: Examples of **correct** code for this rule:
39+
40+
<eslint-code-block fix>
41+
42+
<!-- eslint-skip -->
43+
44+
```vue
45+
<script>
46+
/* eslint @intlify/vue-i18n/no-i18n-t-path-prop: 'error' */
47+
</script>
48+
<template>
49+
<div class="app">
50+
<!-- ✓ GOOD -->
51+
<i18n-t keypath="message.greeting" />
52+
53+
<!-- ✓ GOOD -->
54+
<i18n path="message.greeting" />
55+
</div>
56+
</template>
57+
```
58+
59+
</eslint-code-block>
60+
61+
## :books: Further reading
62+
63+
- [Vue I18n > Breaking Changes - Rename to `keypath` prop from `path` prop](https://vue-i18n.intlify.dev/guide/migration/breaking.html#rename-to-keypath-prop-from-path-prop)
64+
65+
## :mag: Implementation
66+
67+
- [Rule source](https://github.com/intlify/eslint-plugin-vue-i18n/blob/master/lib/rules/no-i18n-t-path-prop.ts)
68+
- [Test source](https://github.com/intlify/eslint-plugin-vue-i18n/tree/master/tests/lib/rules/no-i18n-t-path-prop.ts)

lib/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import noDeprecatedI18nPlaceAttr from './rules/no-deprecated-i18n-place-attr'
55
import noDuplicateKeysInLocale from './rules/no-duplicate-keys-in-locale'
66
import noDynamicKeys from './rules/no-dynamic-keys'
77
import noHtmlMessages from './rules/no-html-messages'
8+
import noI18nTPathProp from './rules/no-i18n-t-path-prop'
89
import noMissingKeysInOtherLocales from './rules/no-missing-keys-in-other-locales'
910
import noMissingKeys from './rules/no-missing-keys'
1011
import noRawText from './rules/no-raw-text'
@@ -20,6 +21,7 @@ export = {
2021
'no-duplicate-keys-in-locale': noDuplicateKeysInLocale,
2122
'no-dynamic-keys': noDynamicKeys,
2223
'no-html-messages': noHtmlMessages,
24+
'no-i18n-t-path-prop': noI18nTPathProp,
2325
'no-missing-keys-in-other-locales': noMissingKeysInOtherLocales,
2426
'no-missing-keys': noMissingKeys,
2527
'no-raw-text': noRawText,

lib/rules/no-i18n-t-path-prop.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @author Yosuke Ota
3+
*/
4+
import {
5+
defineTemplateBodyVisitor,
6+
getAttribute,
7+
getDirective
8+
} from '../utils/index'
9+
import type { RuleContext, RuleListener } from '../types'
10+
import type { AST as VAST } from 'vue-eslint-parser'
11+
12+
function create(context: RuleContext): RuleListener {
13+
return defineTemplateBodyVisitor(context, {
14+
VElement(node: VAST.VElement) {
15+
if (node.name !== 'i18n-t') {
16+
return
17+
}
18+
const pathProp =
19+
getAttribute(node, 'path') || getDirective(node, 'bind', 'path')
20+
if (pathProp) {
21+
context.report({
22+
node: pathProp.key,
23+
messageId: 'disallow',
24+
fix(fixer) {
25+
if (pathProp.directive) {
26+
return fixer.replaceText(pathProp.key.argument!, 'keypath')
27+
} else {
28+
return fixer.replaceText(pathProp.key, 'keypath')
29+
}
30+
}
31+
})
32+
}
33+
}
34+
})
35+
}
36+
37+
export = {
38+
meta: {
39+
type: 'problem',
40+
docs: {
41+
description: 'disallow using `path` prop with `<i18n-t>`',
42+
category: 'Recommended',
43+
recommended: false
44+
},
45+
fixable: 'code',
46+
schema: [],
47+
messages: {
48+
disallow:
49+
'Cannot use `path` prop with `<i18n-t>` component. Use `keypath` prop instead.'
50+
}
51+
},
52+
create
53+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* @author Yosuke Ota
3+
*/
4+
import { RuleTester } from 'eslint'
5+
import rule = require('../../../lib/rules/no-i18n-t-path-prop')
6+
7+
const tester = new RuleTester({
8+
parser: require.resolve('vue-eslint-parser'),
9+
parserOptions: { ecmaVersion: 2015 }
10+
})
11+
12+
tester.run('no-i18n-t-path-prop', rule as never, {
13+
valid: [
14+
{
15+
code: `
16+
<template>
17+
<i18n-t keypath="message.greeting" />
18+
</template>
19+
`
20+
},
21+
{
22+
code: `
23+
<template>
24+
<i18n path="message.greeting" />
25+
</template>
26+
`
27+
}
28+
],
29+
invalid: [
30+
{
31+
code: `
32+
<template>
33+
<i18n-t path="message.greeting" />
34+
</template>
35+
`,
36+
output: `
37+
<template>
38+
<i18n-t keypath="message.greeting" />
39+
</template>
40+
`,
41+
errors: [
42+
{
43+
message:
44+
'Cannot use `path` prop with `<i18n-t>` component. Use `keypath` prop instead.',
45+
line: 3,
46+
column: 17
47+
}
48+
]
49+
},
50+
{
51+
code: `
52+
<template>
53+
<i18n-t :path="messageKey" />
54+
</template>
55+
`,
56+
output: `
57+
<template>
58+
<i18n-t :keypath="messageKey" />
59+
</template>
60+
`,
61+
errors: [
62+
{
63+
message:
64+
'Cannot use `path` prop with `<i18n-t>` component. Use `keypath` prop instead.',
65+
line: 3,
66+
column: 17
67+
}
68+
]
69+
},
70+
{
71+
code: `
72+
<template>
73+
<i18n-t v-bind:path="messageKey" />
74+
</template>
75+
`,
76+
output: `
77+
<template>
78+
<i18n-t v-bind:keypath="messageKey" />
79+
</template>
80+
`,
81+
errors: [
82+
{
83+
message:
84+
'Cannot use `path` prop with `<i18n-t>` component. Use `keypath` prop instead.',
85+
line: 3,
86+
column: 17
87+
}
88+
]
89+
}
90+
]
91+
})

0 commit comments

Comments
 (0)