Skip to content

Commit e4f71bd

Browse files
committed
Fix false positives for mixin in one-component-per-file and require-name-property rule
1 parent 3168819 commit e4f71bd

File tree

5 files changed

+70
-27
lines changed

5 files changed

+70
-27
lines changed

lib/rules/one-component-per-file.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
'use strict'
66
const utils = require('../utils')
7+
const { getVueComponentDefinitionType } = require('../utils')
78

89
// ------------------------------------------------------------------------------
910
// Rule Definition
@@ -30,7 +31,13 @@ module.exports = {
3031

3132
return Object.assign(
3233
{},
33-
utils.executeOnVueComponent(context, (node) => {
34+
utils.executeOnVueComponent(context, (node, type) => {
35+
if (type === 'definition') {
36+
const defType = getVueComponentDefinitionType(node)
37+
if (defType === 'mixin') {
38+
return
39+
}
40+
}
3441
components.push(node)
3542
}),
3643
{

lib/rules/require-name-property.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
'use strict'
66

77
const utils = require('../utils')
8+
const { getVueComponentDefinitionType } = require('../utils')
89

910
/**
1011
* @param {Property | SpreadElement} node
@@ -31,7 +32,14 @@ module.exports = {
3132
},
3233
/** @param {RuleContext} context */
3334
create(context) {
34-
return utils.executeOnVue(context, (component) => {
35+
return utils.executeOnVue(context, (component, type) => {
36+
if (type === 'definition') {
37+
const defType = getVueComponentDefinitionType(component)
38+
if (defType === 'mixin') {
39+
return
40+
}
41+
}
42+
3543
if (component.properties.some(isNameProperty)) return
3644

3745
context.report({

lib/utils/index.js

+36-25
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,13 @@ module.exports = {
10031003
},
10041004

10051005
getVueObjectType,
1006+
/**
1007+
* Get the Vue component definition type from given node
1008+
* Vue.component('xxx', {}) || component('xxx', {})
1009+
* @param {ObjectExpression} node Node to check
1010+
* @returns {'component' | 'mixin' | 'extend' | 'createApp' | 'defineComponent' | null}
1011+
*/
1012+
getVueComponentDefinitionType,
10061013
compositingVisitors,
10071014

10081015
/**
@@ -1876,14 +1883,15 @@ function isVueComponentFile(node, path) {
18761883
}
18771884

18781885
/**
1879-
* Check whether given node is Vue component
1886+
* Get the Vue component definition type from given node
18801887
* Vue.component('xxx', {}) || component('xxx', {})
1881-
* @param {ESNode} node Node to check
1882-
* @returns {boolean}
1888+
* @param {ObjectExpression} node Node to check
1889+
* @returns {'component' | 'mixin' | 'extend' | 'createApp' | 'defineComponent' | null}
18831890
*/
1884-
function isVueComponent(node) {
1885-
if (node.type === 'CallExpression') {
1886-
const callee = node.callee
1891+
function getVueComponentDefinitionType(node) {
1892+
const parent = getParent(node)
1893+
if (parent.type === 'CallExpression') {
1894+
const callee = parent.callee
18871895

18881896
if (callee.type === 'MemberExpression') {
18891897
const calleeObject = skipTSAsExpression(callee.object)
@@ -1893,48 +1901,51 @@ function isVueComponent(node) {
18931901
if (calleeObject.name === 'Vue') {
18941902
// for Vue.js 2.x
18951903
// Vue.component('xxx', {}) || Vue.mixin({}) || Vue.extend('xxx', {})
1896-
const isFullVueComponentForVue2 =
1897-
propName &&
1898-
['component', 'mixin', 'extend'].includes(propName) &&
1899-
isObjectArgument(node)
1900-
1901-
return Boolean(isFullVueComponentForVue2)
1904+
const maybeFullVueComponentForVue2 =
1905+
propName && isObjectArgument(parent)
1906+
1907+
return maybeFullVueComponentForVue2 &&
1908+
(propName === 'component' ||
1909+
propName === 'mixin' ||
1910+
propName === 'extend')
1911+
? propName
1912+
: null
19021913
}
19031914

19041915
// for Vue.js 3.x
19051916
// app.component('xxx', {}) || app.mixin({})
1906-
const isFullVueComponent =
1907-
propName &&
1908-
['component', 'mixin'].includes(propName) &&
1909-
isObjectArgument(node)
1917+
const maybeFullVueComponent = propName && isObjectArgument(parent)
19101918

1911-
return Boolean(isFullVueComponent)
1919+
return maybeFullVueComponent &&
1920+
(propName === 'component' || propName === 'mixin')
1921+
? propName
1922+
: null
19121923
}
19131924
}
19141925

19151926
if (callee.type === 'Identifier') {
19161927
if (callee.name === 'component') {
19171928
// for Vue.js 2.x
19181929
// component('xxx', {})
1919-
const isDestructedVueComponent = isObjectArgument(node)
1920-
return isDestructedVueComponent
1930+
const isDestructedVueComponent = isObjectArgument(parent)
1931+
return isDestructedVueComponent ? 'component' : null
19211932
}
19221933
if (callee.name === 'createApp') {
19231934
// for Vue.js 3.x
19241935
// createApp({})
1925-
const isAppVueComponent = isObjectArgument(node)
1926-
return isAppVueComponent
1936+
const isAppVueComponent = isObjectArgument(parent)
1937+
return isAppVueComponent ? 'createApp' : null
19271938
}
19281939
if (callee.name === 'defineComponent') {
19291940
// for Vue.js 3.x
19301941
// defineComponent({})
1931-
const isDestructedVueComponent = isObjectArgument(node)
1932-
return isDestructedVueComponent
1942+
const isDestructedVueComponent = isObjectArgument(parent)
1943+
return isDestructedVueComponent ? 'defineComponent' : null
19331944
}
19341945
}
19351946
}
19361947

1937-
return false
1948+
return null
19381949

19391950
/** @param {CallExpression} node */
19401951
function isObjectArgument(node) {
@@ -1986,7 +1997,7 @@ function getVueObjectType(context, node) {
19861997
} else if (parent.type === 'CallExpression') {
19871998
// Vue.component('xxx', {}) || component('xxx', {})
19881999
if (
1989-
isVueComponent(parent) &&
2000+
getVueComponentDefinitionType(node) != null &&
19902001
skipTSAsExpression(parent.arguments.slice(-1)[0]) === node
19912002
) {
19922003
return 'definition'

tests/lib/rules/one-component-per-file.js

+7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ ruleTester.run('one-component-per-file', rule, {
5151
}
5252
}
5353
}`
54+
},
55+
{
56+
filename: 'test.js',
57+
code: `
58+
Vue.mixin({})
59+
Vue.component('name', {})
60+
`
5461
}
5562
],
5663
invalid: [

tests/lib/rules/require-name-property.js

+10
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ ruleTester.run('require-name-property', rule, {
4141
}
4242
`,
4343
parserOptions
44+
},
45+
{
46+
code: `
47+
Vue.mixin({
48+
methods: {
49+
$foo () {}
50+
}
51+
})
52+
`,
53+
parserOptions
4454
}
4555
],
4656

0 commit comments

Comments
 (0)