Skip to content

Commit d012df0

Browse files
authored
Add @intlify/vue-i18n/no-deprecated-i18n-places-prop rule (#166)
1 parent 2d7739b commit d012df0

File tree

5 files changed

+245
-0
lines changed

5 files changed

+245
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| Rule ID | Description | |
1010
|:--------|:------------|:---|
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: |
12+
| [@intlify/vue-i18n/<wbr>no-deprecated-i18n-places-prop](./no-deprecated-i18n-places-prop.html) | disallow using deprecated `places` prop (Removed in Vue I18n 9.0.0+) | |
1213
| [@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+) | |
1314
| [@intlify/vue-i18n/<wbr>no-html-messages](./no-html-messages.html) | disallow use HTML localization messages | :star: |
1415
| [@intlify/vue-i18n/<wbr>no-i18n-t-path-prop](./no-i18n-t-path-prop.html) | disallow using `path` prop with `<i18n-t>` | :black_nib: |
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
title: '@intlify/vue-i18n/no-deprecated-i18n-places-prop'
3+
description: disallow using deprecated `places` prop (Removed in Vue I18n 9.0.0+)
4+
---
5+
6+
# @intlify/vue-i18n/no-deprecated-i18n-places-prop
7+
8+
> disallow using deprecated `places` prop (Removed in Vue I18n 9.0.0+)
9+
10+
If you are migrating from Vue I18n v8 to v9, the `places` prop should be replaced with the `v-slot`.
11+
12+
## :book: Rule Details
13+
14+
This rule reports use of deprecated `places` prop (Removed in Vue I18n 9.0.0+).
15+
16+
:-1: Examples of **incorrect** code for this rule:
17+
18+
<eslint-code-block>
19+
20+
<!-- eslint-skip -->
21+
22+
```vue
23+
<script>
24+
/* eslint @intlify/vue-i18n/no-deprecated-i18n-places-prop: 'error' */
25+
</script>
26+
<template>
27+
<div class="app">
28+
<!-- ✗ BAD -->
29+
<i18n path="info" tag="p" :places="{ limit: changeLimit }">
30+
<a place="action" :href="changeUrl">{{ $t('change') }}</a>
31+
</i18n>
32+
33+
<!-- Also check the <i18n-t> component to prevent mistakes. -->
34+
<!-- ✗ BAD -->
35+
<i18n-t path="info" tag="p" :places="{ limit: changeLimit }">
36+
<a place="action" :href="changeUrl">{{ $t('change') }}</a>
37+
</i18n-t>
38+
</div>
39+
</template>
40+
```
41+
42+
</eslint-code-block>
43+
44+
:+1: Examples of **correct** code for this rule:
45+
46+
<eslint-code-block>
47+
48+
<!-- eslint-skip -->
49+
50+
```vue
51+
<script>
52+
/* eslint @intlify/vue-i18n/no-deprecated-i18n-places-prop: 'error' */
53+
</script>
54+
<template>
55+
<div class="app">
56+
<!-- ✓ GOOD -->
57+
<i18n path="info" tag="p">
58+
<template v-slot:limit>
59+
<span>{{ changeLimit }}</span>
60+
</template>
61+
<template v-slot:action>
62+
<a :href="changeUrl">{{ $t('change') }}</a>
63+
</template>
64+
</i18n>
65+
66+
<!-- ✓ GOOD -->
67+
<i18n-t keypath="info" tag="p">
68+
<template #limit>
69+
<span>{{ changeLimit }}</span>
70+
</template>
71+
<template #action>
72+
<a :href="changeUrl">{{ $t('change') }}</a>
73+
</template>
74+
</i18n-t>
75+
</div>
76+
</template>
77+
```
78+
79+
</eslint-code-block>
80+
81+
## :books: Further reading
82+
83+
- [Vue I18n > Breaking Changes - Remove place syntax with `place` attr and `places` prop](https://vue-i18n.intlify.dev/guide/migration/breaking.html#remove-place-syntax-with-place-attr-and-places-prop)
84+
- [Vue I18n (v8) > Component interpolation - Places syntax usage](https://kazupon.github.io/vue-i18n/guide/interpolation.html#places-syntax-usage)
85+
86+
## :mag: Implementation
87+
88+
- [Rule source](https://github.com/intlify/eslint-plugin-vue-i18n/blob/master/lib/rules/no-deprecated-i18n-places-prop.ts)
89+
- [Test source](https://github.com/intlify/eslint-plugin-vue-i18n/tree/master/tests/lib/rules/no-deprecated-i18n-places-prop.ts)

lib/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** DON'T EDIT THIS FILE; was created by scripts. */
22
import keyFormatStyle from './rules/key-format-style'
33
import noDeprecatedI18nComponent from './rules/no-deprecated-i18n-component'
4+
import noDeprecatedI18nPlacesProp from './rules/no-deprecated-i18n-places-prop'
45
import noDeprecatedI18nPlaceAttr from './rules/no-deprecated-i18n-place-attr'
56
import noDuplicateKeysInLocale from './rules/no-duplicate-keys-in-locale'
67
import noDynamicKeys from './rules/no-dynamic-keys'
@@ -17,6 +18,7 @@ import validMessageSyntax from './rules/valid-message-syntax'
1718
export = {
1819
'key-format-style': keyFormatStyle,
1920
'no-deprecated-i18n-component': noDeprecatedI18nComponent,
21+
'no-deprecated-i18n-places-prop': noDeprecatedI18nPlacesProp,
2022
'no-deprecated-i18n-place-attr': noDeprecatedI18nPlaceAttr,
2123
'no-duplicate-keys-in-locale': noDuplicateKeysInLocale,
2224
'no-dynamic-keys': noDynamicKeys,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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' && node.name !== 'i18n-t') {
16+
return
17+
}
18+
const placesProp =
19+
getAttribute(node, 'places') || getDirective(node, 'bind', 'places')
20+
if (placesProp) {
21+
context.report({
22+
node: placesProp.key,
23+
messageId: 'deprecated'
24+
})
25+
}
26+
}
27+
})
28+
}
29+
30+
export = {
31+
meta: {
32+
type: 'problem',
33+
docs: {
34+
description:
35+
'disallow using deprecated `places` prop (Removed in Vue I18n 9.0.0+)',
36+
category: 'Recommended',
37+
recommended: false
38+
},
39+
fixable: null,
40+
schema: [],
41+
messages: {
42+
deprecated: 'Deprecated `places` prop was found. Use v-slot instead.'
43+
}
44+
},
45+
create
46+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* @author Yosuke Ota
3+
*/
4+
import { RuleTester } from 'eslint'
5+
import rule = require('../../../lib/rules/no-deprecated-i18n-places-prop')
6+
7+
const tester = new RuleTester({
8+
parser: require.resolve('vue-eslint-parser'),
9+
parserOptions: { ecmaVersion: 2015 }
10+
})
11+
12+
tester.run('no-deprecated-i18n-places-prop', rule as never, {
13+
valid: [
14+
{
15+
code: `
16+
<template>
17+
<div id="app">
18+
<!-- ... -->
19+
<i18n path="info" tag="p">
20+
<template v-slot:limit>
21+
<span>{{ changeLimit }}</span>
22+
</template>
23+
<template v-slot:action>
24+
<a :href="changeUrl">{{ $t('change') }}</a>
25+
</template>
26+
</i18n>
27+
<!-- ... -->
28+
</div>
29+
</template>
30+
`
31+
},
32+
{
33+
code: `
34+
<template>
35+
<div id="app">
36+
<!-- ... -->
37+
<i18n path="info" tag="p">
38+
<template #limit>
39+
<span>{{ changeLimit }}</span>
40+
</template>
41+
<template #action>
42+
<a :href="changeUrl">{{ $t('change') }}</a>
43+
</template>
44+
</i18n>
45+
<!-- ... -->
46+
</div>
47+
</template>
48+
`
49+
},
50+
{
51+
code: `
52+
<template>
53+
<div id="app">
54+
<!-- ... -->
55+
<unknown-component path="info" tag="p" :places="{ limit: changeLimit }">
56+
<a place="action" :href="changeUrl">{{ $t('change') }}</a>
57+
</unknown-component>
58+
<!-- ... -->
59+
</div>
60+
</template>
61+
`
62+
}
63+
],
64+
invalid: [
65+
{
66+
code: `
67+
<template>
68+
<div id="app">
69+
<!-- ... -->
70+
<i18n path="info" tag="p" :places="{ limit: changeLimit }">
71+
<a place="action" :href="changeUrl">{{ $t('change') }}</a>
72+
</i18n>
73+
<!-- ... -->
74+
</div>
75+
</template>
76+
`,
77+
errors: [
78+
{
79+
message: 'Deprecated `places` prop was found. Use v-slot instead.',
80+
line: 5,
81+
column: 37
82+
}
83+
]
84+
},
85+
86+
{
87+
code: `
88+
<template>
89+
<div id="app">
90+
<!-- ... -->
91+
<i18n-t path="info" tag="p" :places="{ limit: changeLimit }">
92+
<a place="action" :href="changeUrl">{{ $t('change') }}</a>
93+
</i18n-t>
94+
<!-- ... -->
95+
</div>
96+
</template>
97+
`,
98+
errors: [
99+
{
100+
message: 'Deprecated `places` prop was found. Use v-slot instead.',
101+
line: 5,
102+
column: 39
103+
}
104+
]
105+
}
106+
]
107+
})

0 commit comments

Comments
 (0)