-
-
Notifications
You must be signed in to change notification settings - Fork 704
fix(one-component-per-file): Ignore members imported from elsewhere #3063
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
d61c64b
455a655
6311de6
eb13341
d881d20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| 'eslint-plugin-vue': patch | ||
| --- | ||
|
|
||
| Ignore members imported from elsewhere in `vue/one-component-per-file` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2186,11 +2186,7 @@ module.exports = { | |
| * Wraps composition API trace map in both 'vue' and '@vue/composition-api' imports, or '#imports' from unimport | ||
| * @param {import('@eslint-community/eslint-utils').TYPES.TraceMap} map | ||
| */ | ||
| createCompositionApiTraceMap: (map) => ({ | ||
| vue: map, | ||
| '@vue/composition-api': map, | ||
| '#imports': map | ||
| }), | ||
| createCompositionApiTraceMap, | ||
|
|
||
| /** | ||
| * Iterates all references in the given trace map. | ||
|
|
@@ -2727,13 +2723,85 @@ function isVueComponentFile(node, path) { | |
| ) | ||
| } | ||
|
|
||
| /** | ||
| * Whether the given callee refers to a symbol exported by Vue. | ||
| * @param {Identifier} callee Node to check. | ||
| * @param {RuleContext} context The rule context to use parser services. | ||
| * @returns {boolean} | ||
| */ | ||
| function isGlobalOrImportedFromVue(callee, context) { | ||
| const globalScope = context.sourceCode.scopeManager.globalScope | ||
|
|
||
| if (globalScope === null) { | ||
| return true | ||
| } | ||
|
|
||
| const tracker = new ReferenceTracker(globalScope) | ||
|
|
||
| const globalTraceMap = { | ||
| [callee.name]: { | ||
| [ReferenceTracker.CALL]: true | ||
| } | ||
| } | ||
| const cjsTraceMap = createCompositionApiTraceMap(globalTraceMap) | ||
| const esmTraceMap = createCompositionApiTraceMap({ | ||
| [ReferenceTracker.ESM]: true, | ||
| [callee.name]: { | ||
| [ReferenceTracker.CALL]: true | ||
| } | ||
| }) | ||
|
|
||
| function* allReferences() { | ||
| yield* tracker.iterateGlobalReferences(globalTraceMap) | ||
| yield* tracker.iterateEsmReferences(esmTraceMap) | ||
| yield* tracker.iterateCjsReferences(cjsTraceMap) | ||
| } | ||
|
|
||
| for (const { node } of allReferences()) { | ||
| if (node === callee.parent) { | ||
| return true | ||
| } | ||
| } | ||
|
|
||
| // No references found | ||
| // The callee is either from a different source, or it is injected | ||
| // (e.g., <script>defineComponent({})</script>). | ||
|
|
||
| const variable = findVariable(getScope(context, callee), callee) | ||
|
|
||
| // console.log('foobarr', context.sourceCode.text, variable?.defs[0]) | ||
|
|
||
| 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' && | ||
| def.node.parent.source.value !== '@vue/composition-api' | ||
| ) { | ||
| return false | ||
| } | ||
|
|
||
| // ignore `function name() {}` | ||
| if (def.type === 'FunctionName') { | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| return true | ||
| } | ||
|
|
||
| /** | ||
| * 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' | 'defineNuxtComponent' | null} | ||
| */ | ||
| function getVueComponentDefinitionType(node) { | ||
| function getVueComponentDefinitionType(context, node) { | ||
| const parent = getParent(node) | ||
| if (parent.type === 'CallExpression') { | ||
| const callee = parent.callee | ||
|
|
@@ -2769,6 +2837,17 @@ function getVueComponentDefinitionType(node) { | |
| } | ||
|
|
||
| if (callee.type === 'Identifier') { | ||
| if (callee.name === 'defineNuxtComponent') { | ||
| // for Nuxt 3.x | ||
| // defineNuxtComponent({}) | ||
| const isDestructedVueComponent = isObjectArgument(parent) | ||
| return isDestructedVueComponent ? 'defineNuxtComponent' : null | ||
InSyncWithFoo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| if (!isGlobalOrImportedFromVue(callee, context)) { | ||
|
||
| return null | ||
| } | ||
|
|
||
InSyncWithFoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (callee.name === 'component') { | ||
| // for Vue.js 2.x | ||
| // component('xxx', {}) | ||
|
|
@@ -2787,12 +2866,6 @@ function getVueComponentDefinitionType(node) { | |
| const isDestructedVueComponent = isObjectArgument(parent) | ||
| return isDestructedVueComponent ? 'defineComponent' : null | ||
| } | ||
| if (callee.name === 'defineNuxtComponent') { | ||
| // for Nuxt 3.x | ||
| // defineNuxtComponent({}) | ||
| const isDestructedVueComponent = isObjectArgument(parent) | ||
| return isDestructedVueComponent ? 'defineNuxtComponent' : null | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -2860,7 +2933,7 @@ function getVueObjectType(context, node) { | |
| case 'CallExpression': { | ||
| // Vue.component('xxx', {}) || component('xxx', {}) | ||
| if ( | ||
| getVueComponentDefinitionType(node) != null && | ||
| getVueComponentDefinitionType(context, node) != null && | ||
| skipTSAsExpression(parent.arguments.at(-1)) === node | ||
| ) { | ||
| return 'definition' | ||
|
|
@@ -3010,6 +3083,18 @@ function* iterateWatchHandlerValues(property) { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Wraps composition API trace map in both 'vue' and '@vue/composition-api' imports, or '#imports' from unimport | ||
| * @param {import('@eslint-community/eslint-utils').TYPES.TraceMap} map | ||
| */ | ||
| function createCompositionApiTraceMap(map) { | ||
| return { | ||
| vue: map, | ||
| '@vue/composition-api': map, | ||
| '#imports': map | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Get the attribute which has the given name. | ||
| * @param {VElement} node The start tag node to check. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.