Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion lib/rules/one-component-per-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module.exports = {
{},
utils.executeOnVueComponent(context, (node, type) => {
if (type === 'definition') {
const defType = getVueComponentDefinitionType(node)
const defType = getVueComponentDefinitionType(context, node)
if (defType === 'mixin') {
return
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/require-expose.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ module.exports = {
return
}
if (type === 'definition') {
const defType = getVueComponentDefinitionType(component)
const defType = getVueComponentDefinitionType(context, component)
if (defType === 'mixin') {
return
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/require-name-property.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ module.exports = {
}
return utils.executeOnVue(context, (component, type) => {
if (type === 'definition') {
const defType = getVueComponentDefinitionType(component)
const defType = getVueComponentDefinitionType(context, component)
if (defType === 'mixin') {
return
}
Expand Down
22 changes: 20 additions & 2 deletions lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2479,10 +2479,11 @@ function isVueComponentFile(node, path) {
/**
* Get the Vue component definition type from given node
* Vue.component('xxx', {}) || component('xxx', {})
* @param {RuleContext} context The rule context to use parser services.
* @param {ObjectExpression} node Node to check
* @returns {'component' | 'mixin' | 'extend' | 'createApp' | 'defineComponent' | null}
*/
function getVueComponentDefinitionType(node) {
function getVueComponentDefinitionType(context, node) {
const parent = getParent(node)
if (parent.type === 'CallExpression') {
const callee = parent.callee
Expand Down Expand Up @@ -2527,6 +2528,23 @@ function getVueComponentDefinitionType(node) {
if (callee.name === 'createApp') {
// for Vue.js 3.x
// createApp({})

const variable = findVariable(context.getScope(), callee)
Copy link
Member

Choose a reason for hiding this comment

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

Sorry for the late reply. I am busy with office work.

I think it can be written more simply using tracker.iterateEsmReferences.

https://eslint-community.github.io/eslint-utils/api/scope-utils.html#tracker-iterateesmreferences

e.g.

          const tracker = new ReferenceTracker(context.getSourceCode().scopeManager.globalScope)
          const traceMap = utils.createCompositionApiTraceMap({
            [ReferenceTracker.ESM]: true,
            createApp: {
              [ReferenceTracker.CALL]: true
            }
          })
          if ([...tracker.iterateEsmReferences(traceMap)].every(({ node }) => node !== callee)) {
            return null;
          }

Copy link
Member

Choose a reason for hiding this comment

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

@candy-Tong Would you like to give this a try?


// only lint the createApp function that import from vue
if (variable !== null && variable.defs.length === 1) {
const def = variable.defs[0]
if (
def.type === 'ImportBinding' &&
def.node.type === 'ImportSpecifier' &&
def.node.imported.type === 'Identifier' &&
def.node.parent.type === 'ImportDeclaration' &&
def.node.parent.source.value !== 'vue'
) {
return null
}
}

const isAppVueComponent = isObjectArgument(parent)
return isAppVueComponent ? 'createApp' : null
}
Expand Down Expand Up @@ -2603,7 +2621,7 @@ function getVueObjectType(context, node) {
case 'CallExpression': {
// Vue.component('xxx', {}) || component('xxx', {})
if (
getVueComponentDefinitionType(node) != null &&
getVueComponentDefinitionType(context, node) != null &&
skipTSAsExpression(parent.arguments.slice(-1)[0]) === node
) {
return 'definition'
Expand Down
27 changes: 27 additions & 0 deletions tests/lib/rules/one-component-per-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ ruleTester.run('one-component-per-file', rule, {
Vue.mixin({})
Vue.component('name', {})
`
},
{
filename: 'test.js',
code: `
import { createApp } from 'vue'
createApp({})
`
},
{
filename: 'test.js',
code: `
import { createApp } from 'other.js'
createApp({})
createApp({})
`
}
],
invalid: [
Expand Down Expand Up @@ -95,6 +110,18 @@ ruleTester.run('one-component-per-file', rule, {
'There is more than one component in this file.',
'There is more than one component in this file.'
]
},
{
filename: 'test.vue',
code: `
import { createApp } from 'vue'
createApp({})
createApp({})
`,
errors: [
'There is more than one component in this file.',
'There is more than one component in this file.'
]
}
]
})