Skip to content

Commit e928e4c

Browse files
authored
Add composition-vue2 style in vue/component-api-style (#1703)
* Add `composition-vue2` api style * Improve error message * Also allow `renderTracked` and `renderTriggered`
1 parent c033ac6 commit e928e4c

File tree

3 files changed

+336
-57
lines changed

3 files changed

+336
-57
lines changed

docs/rules/component-api-style.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,15 @@ export default {
7373
```json
7474
{
7575
"vue/component-api-style": ["error",
76-
["script-setup", "composition"] // "script-setup", "composition", or "options"
76+
["script-setup", "composition"] // "script-setup", "composition", "composition-vue2", or "options"
7777
]
7878
}
7979
```
8080

8181
- Array options ... Defines the API styles you want to allow. Default is `["script-setup", "composition"]`. You can use the following values.
82-
- `"script-setup"` ... If set, allows `<script setup>`.
83-
- `"composition"` ... If set, allows Composition API (not `<script setup>`).
82+
- `"script-setup"` ... If set, allows [`<script setup>`](https://v3.vuejs.org/api/sfc-script-setup.html).
83+
- `"composition"` ... If set, allows [Composition API](https://v3.vuejs.org/api/composition-api.html) (not `<script setup>`).
84+
- `"composition-vue2"` ... If set, allows [Composition API for Vue 2](https://github.com/vuejs/composition-api) (not `<script setup>`). In particular, it allows `render`, `renderTracked` and `renderTriggered` alongside `setup`.
8485
- `"options"` ... If set, allows Options API.
8586

8687
### `["options"]`

lib/rules/component-api-style.js

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,29 @@
77
const utils = require('../utils')
88

99
/**
10-
* @typedef { 'script-setup' | 'composition' | 'options' } PreferOption
10+
* @typedef { 'script-setup' | 'composition' | 'composition-vue2' | 'options' } PreferOption
1111
*
1212
* @typedef {PreferOption[]} UserPreferOption
1313
*
1414
* @typedef {object} NormalizeOptions
1515
* @property {object} allowsSFC
1616
* @property {boolean} [allowsSFC.scriptSetup]
1717
* @property {boolean} [allowsSFC.composition]
18+
* @property {boolean} [allowsSFC.compositionVue2]
1819
* @property {boolean} [allowsSFC.options]
1920
* @property {object} allowsOther
2021
* @property {boolean} [allowsOther.composition]
22+
* @property {boolean} [allowsOther.compositionVue2]
2123
* @property {boolean} [allowsOther.options]
2224
*/
2325

2426
/** @type {PreferOption[]} */
25-
const STYLE_OPTIONS = ['script-setup', 'composition', 'options']
27+
const STYLE_OPTIONS = [
28+
'script-setup',
29+
'composition',
30+
'composition-vue2',
31+
'options'
32+
]
2633

2734
/**
2835
* Normalize options.
@@ -41,14 +48,22 @@ function parseOptions(options) {
4148
} else if (prefer === 'composition') {
4249
opts.allowsSFC.composition = true
4350
opts.allowsOther.composition = true
51+
} else if (prefer === 'composition-vue2') {
52+
opts.allowsSFC.compositionVue2 = true
53+
opts.allowsOther.compositionVue2 = true
4454
} else if (prefer === 'options') {
4555
opts.allowsSFC.options = true
4656
opts.allowsOther.options = true
4757
}
4858
}
4959

50-
if (!opts.allowsOther.composition && !opts.allowsOther.options) {
60+
if (
61+
!opts.allowsOther.composition &&
62+
!opts.allowsOther.compositionVue2 &&
63+
!opts.allowsOther.options
64+
) {
5165
opts.allowsOther.composition = true
66+
opts.allowsOther.compositionVue2 = true
5267
opts.allowsOther.options = true
5368
}
5469

@@ -87,6 +102,13 @@ const OPTIONS_API_OPTIONS = new Set([
87102
])
88103
const COMPOSITION_API_OPTIONS = new Set(['setup'])
89104

105+
const COMPOSITION_API_VUE2_OPTIONS = new Set([
106+
'setup',
107+
'render', // https://github.com/vuejs/composition-api#template-refs
108+
'renderTracked', // https://github.com/vuejs/composition-api#missing-apis
109+
'renderTriggered' // https://github.com/vuejs/composition-api#missing-apis
110+
])
111+
90112
const LIFECYCLE_HOOK_OPTIONS = new Set([
91113
'beforeCreate',
92114
'created',
@@ -113,6 +135,7 @@ const LIFECYCLE_HOOK_OPTIONS = new Set([
113135
* @param {object} allowsOpt
114136
* @param {boolean} [allowsOpt.scriptSetup]
115137
* @param {boolean} [allowsOpt.composition]
138+
* @param {boolean} [allowsOpt.compositionVue2]
116139
* @param {boolean} [allowsOpt.options]
117140
*/
118141
function buildAllowedPhrase(allowsOpt) {
@@ -123,6 +146,9 @@ function buildAllowedPhrase(allowsOpt) {
123146
if (allowsOpt.composition) {
124147
phrases.push('Composition API')
125148
}
149+
if (allowsOpt.compositionVue2) {
150+
phrases.push('Composition API (Vue 2)')
151+
}
126152
if (allowsOpt.options) {
127153
phrases.push('Options API')
128154
}
@@ -135,10 +161,16 @@ function buildAllowedPhrase(allowsOpt) {
135161
* @param {object} allowsOpt
136162
* @param {boolean} [allowsOpt.scriptSetup]
137163
* @param {boolean} [allowsOpt.composition]
164+
* @param {boolean} [allowsOpt.compositionVue2]
138165
* @param {boolean} [allowsOpt.options]
139166
*/
140167
function isPreferScriptSetup(allowsOpt) {
141-
if (!allowsOpt.scriptSetup || allowsOpt.composition || allowsOpt.options) {
168+
if (
169+
!allowsOpt.scriptSetup ||
170+
allowsOpt.composition ||
171+
allowsOpt.compositionVue2 ||
172+
allowsOpt.options
173+
) {
142174
return false
143175
}
144176
return true
@@ -179,7 +211,7 @@ module.exports = {
179211
disallowScriptSetup:
180212
'`<script setup>` is not allowed in your project. Use {{allowedApis}} instead.',
181213
disallowComponentOption:
182-
'{{disallowedApi}} is not allowed in your project. {{optionPhrase}} is the API of {{disallowedApi}}. Use {{allowedApis}} instead.',
214+
'{{disallowedApi}} is not allowed in your project. {{optionPhrase}} is part of the {{disallowedApi}}. Use {{allowedApis}} instead.',
183215
disallowComponentOptionPreferScriptSetup:
184216
'{{disallowedApi}} is not allowed in your project. Use `<script setup>` instead.'
185217
}
@@ -211,21 +243,29 @@ module.exports = {
211243
const allows = utils.isSFCObject(context, node)
212244
? options.allowsSFC
213245
: options.allowsOther
214-
if (allows.composition && allows.options) {
246+
if (
247+
(allows.composition || allows.compositionVue2) &&
248+
allows.options
249+
) {
215250
return
216251
}
217-
const disallows = [
252+
const apis = [
218253
{
219254
allow: allows.composition,
220255
options: COMPOSITION_API_OPTIONS,
221-
api: 'Composition API'
256+
apiName: 'Composition API'
222257
},
223258
{
224259
allow: allows.options,
225260
options: OPTIONS_API_OPTIONS,
226-
api: 'Options API'
261+
apiName: 'Options API'
262+
},
263+
{
264+
allow: allows.compositionVue2,
265+
options: COMPOSITION_API_VUE2_OPTIONS,
266+
apiName: 'Composition API (Vue 2)'
227267
}
228-
].filter(({ allow }) => !allow)
268+
]
229269
for (const prop of node.properties) {
230270
if (prop.type !== 'Property') {
231271
continue
@@ -234,20 +274,23 @@ module.exports = {
234274
if (!name) {
235275
continue
236276
}
237-
for (const { options, api } of disallows) {
238-
if (options.has(name)) {
239-
context.report({
240-
node: prop.key,
241-
messageId: isPreferScriptSetup(allows)
242-
? 'disallowComponentOptionPreferScriptSetup'
243-
: 'disallowComponentOption',
244-
data: {
245-
disallowedApi: api,
246-
optionPhrase: buildOptionPhrase(name),
247-
allowedApis: buildAllowedPhrase(allows)
248-
}
249-
})
250-
}
277+
const propAllowed = apis.some(
278+
(api) => api.allow && api.options.has(name)
279+
)
280+
if (!propAllowed) {
281+
context.report({
282+
node: prop.key,
283+
messageId: isPreferScriptSetup(allows)
284+
? 'disallowComponentOptionPreferScriptSetup'
285+
: 'disallowComponentOption',
286+
data: {
287+
disallowedApi: apis.filter(
288+
(api) => !api.allow && api.options.has(name)
289+
)[0].apiName,
290+
optionPhrase: buildOptionPhrase(name),
291+
allowedApis: buildAllowedPhrase(allows)
292+
}
293+
})
251294
}
252295
}
253296
}

0 commit comments

Comments
 (0)