fix(compiler-core/compat): fix is prop usage on components
also fix v-bind:is usage on plain element in compat mode fix #3934
This commit is contained in:
@@ -10,7 +10,8 @@ import {
|
||||
assert,
|
||||
advancePositionWithMutation,
|
||||
advancePositionWithClone,
|
||||
isCoreComponent
|
||||
isCoreComponent,
|
||||
isBindKey
|
||||
} from './utils'
|
||||
import {
|
||||
Namespaces,
|
||||
@@ -596,52 +597,20 @@ function parseTag(
|
||||
}
|
||||
|
||||
let tagType = ElementTypes.ELEMENT
|
||||
const options = context.options
|
||||
if (!context.inVPre && !options.isCustomElement(tag)) {
|
||||
const hasVIs = props.some(p => {
|
||||
if (p.name !== 'is') return
|
||||
// v-is="xxx" (TODO: deprecate)
|
||||
if (p.type === NodeTypes.DIRECTIVE) {
|
||||
return true
|
||||
}
|
||||
// is="vue:xxx"
|
||||
if (p.value && p.value.content.startsWith('vue:')) {
|
||||
return true
|
||||
}
|
||||
// in compat mode, any is usage is considered a component
|
||||
if (
|
||||
__COMPAT__ &&
|
||||
checkCompatEnabled(
|
||||
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
|
||||
context,
|
||||
p.loc
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
if (options.isNativeTag && !hasVIs) {
|
||||
if (!options.isNativeTag(tag)) tagType = ElementTypes.COMPONENT
|
||||
} else if (
|
||||
hasVIs ||
|
||||
isCoreComponent(tag) ||
|
||||
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
||||
/^[A-Z]/.test(tag) ||
|
||||
tag === 'component'
|
||||
) {
|
||||
tagType = ElementTypes.COMPONENT
|
||||
}
|
||||
|
||||
if (!context.inVPre) {
|
||||
if (tag === 'slot') {
|
||||
tagType = ElementTypes.SLOT
|
||||
} else if (
|
||||
tag === 'template' &&
|
||||
props.some(
|
||||
p =>
|
||||
p.type === NodeTypes.DIRECTIVE && isSpecialTemplateDirective(p.name)
|
||||
)
|
||||
) {
|
||||
tagType = ElementTypes.TEMPLATE
|
||||
} else if (tag === 'template') {
|
||||
if (
|
||||
props.some(
|
||||
p =>
|
||||
p.type === NodeTypes.DIRECTIVE && isSpecialTemplateDirective(p.name)
|
||||
)
|
||||
) {
|
||||
tagType = ElementTypes.TEMPLATE
|
||||
}
|
||||
} else if (isComponent(tag, props, context)) {
|
||||
tagType = ElementTypes.COMPONENT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,6 +627,65 @@ function parseTag(
|
||||
}
|
||||
}
|
||||
|
||||
function isComponent(
|
||||
tag: string,
|
||||
props: (AttributeNode | DirectiveNode)[],
|
||||
context: ParserContext
|
||||
) {
|
||||
const options = context.options
|
||||
if (options.isCustomElement(tag)) {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
tag === 'component' ||
|
||||
/^[A-Z]/.test(tag) ||
|
||||
isCoreComponent(tag) ||
|
||||
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
||||
(options.isNativeTag && !options.isNativeTag(tag))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
// at this point the tag should be a native tag, but check for potential "is"
|
||||
// casting
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
const p = props[i]
|
||||
if (p.type === NodeTypes.ATTRIBUTE) {
|
||||
if (p.name === 'is' && p.value) {
|
||||
if (p.value.content.startsWith('vue:')) {
|
||||
return true
|
||||
} else if (
|
||||
__COMPAT__ &&
|
||||
checkCompatEnabled(
|
||||
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
|
||||
context,
|
||||
p.loc
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// directive
|
||||
// v-is (TODO Deprecate)
|
||||
if (p.name === 'is') {
|
||||
return true
|
||||
} else if (
|
||||
// :is on plain element - only treat as component in compat mode
|
||||
p.name === 'bind' &&
|
||||
isBindKey(p.arg, 'is') &&
|
||||
__COMPAT__ &&
|
||||
checkCompatEnabled(
|
||||
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
|
||||
context,
|
||||
p.loc
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseAttributes(
|
||||
context: ParserContext,
|
||||
type: TagType
|
||||
|
||||
Reference in New Issue
Block a user