mirror of https://github.com/vuejs/core.git
wip: refine element type
This commit is contained in:
parent
c342433cb5
commit
a12abe72bc
|
@ -18,6 +18,7 @@ import Tokenizer, { CharCodes, QuoteType, isWhitespace } from './Tokenizer'
|
|||
import { CompilerCompatOptions } from '../compat/compatConfig'
|
||||
import { NO, extend } from '@vue/shared'
|
||||
import { defaultOnError, defaultOnWarn } from '../errors'
|
||||
import { isCoreComponent } from '../utils'
|
||||
|
||||
type OptionalOptions =
|
||||
| 'getTextMode' // TODO
|
||||
|
@ -113,8 +114,7 @@ const tokenizer = new Tokenizer({
|
|||
type: NodeTypes.ELEMENT,
|
||||
tag: name,
|
||||
ns: currentOptions.getNamespace(name, getParent()),
|
||||
// TODO refine tag type
|
||||
tagType: ElementTypes.ELEMENT,
|
||||
tagType: ElementTypes.ELEMENT, // will be refined on tag close
|
||||
props: [],
|
||||
children: [],
|
||||
loc: {
|
||||
|
@ -188,8 +188,6 @@ const tokenizer = new Tokenizer({
|
|||
if (name === 'pre') {
|
||||
inVPre = true
|
||||
currentElementIsVPreBoundary = true
|
||||
// force current element type
|
||||
currentElement!.tagType = ElementTypes.ELEMENT
|
||||
// convert dirs before this one to attributes
|
||||
const props = currentElement!.props
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
|
@ -362,9 +360,23 @@ function onCloseTag(el: ElementNode, end: number) {
|
|||
offset++
|
||||
}
|
||||
el.loc.end = tokenizer.getPos(end + offset + 1)
|
||||
|
||||
// refine element type
|
||||
const tag = el.tag
|
||||
if (!inVPre) {
|
||||
if (tag === 'slot') {
|
||||
el.tagType = ElementTypes.SLOT
|
||||
} else if (isFragmentTemplate(el)) {
|
||||
el.tagType = ElementTypes.TEMPLATE
|
||||
} else if (isComponent(el)) {
|
||||
el.tagType = ElementTypes.COMPONENT
|
||||
}
|
||||
}
|
||||
|
||||
// whitepsace management
|
||||
el.children = condenseWhitespace(el.children)
|
||||
if (currentOptions.isPreTag(el.tag)) {
|
||||
|
||||
if (currentOptions.isPreTag(tag)) {
|
||||
inPre--
|
||||
}
|
||||
if (currentElementIsVPreBoundary) {
|
||||
|
@ -373,8 +385,77 @@ function onCloseTag(el: ElementNode, end: number) {
|
|||
}
|
||||
}
|
||||
|
||||
const windowsNewlineRE = /\r\n/g
|
||||
const specialTemplateDir = new Set(['if', 'else', 'else-if', 'for', 'slot'])
|
||||
function isFragmentTemplate({ tag, props }: ElementNode): boolean {
|
||||
if (tag === 'template') {
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
if (
|
||||
props[i].type === NodeTypes.DIRECTIVE &&
|
||||
specialTemplateDir.has(props[i].name)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isComponent({ tag, props }: ElementNode): boolean {
|
||||
if (currentOptions.isCustomElement(tag)) {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
tag === 'component' ||
|
||||
isUpperCase(tag.charCodeAt(0)) ||
|
||||
isCoreComponent(tag) ||
|
||||
currentOptions.isBuiltInComponent?.(tag) ||
|
||||
!currentOptions.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
|
||||
}
|
||||
// TODO else if (
|
||||
// __COMPAT__ &&
|
||||
// checkCompatEnabled(
|
||||
// CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
|
||||
// context,
|
||||
// p.loc
|
||||
// )
|
||||
// ) {
|
||||
// return true
|
||||
// }
|
||||
}
|
||||
}
|
||||
// TODO else if (
|
||||
// __COMPAT__ &&
|
||||
// // :is on plain element - only treat as component in compat mode
|
||||
// p.name === 'bind' &&
|
||||
// isStaticArgOf(p.arg, 'is') &&
|
||||
// checkCompatEnabled(
|
||||
// CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
|
||||
// context,
|
||||
// p.loc
|
||||
// )
|
||||
// ) {
|
||||
// return true
|
||||
// }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isUpperCase(c: number) {
|
||||
return c > 64 && c < 91
|
||||
}
|
||||
|
||||
const windowsNewlineRE = /\r\n/g
|
||||
function condenseWhitespace(nodes: TemplateChildNode[]): TemplateChildNode[] {
|
||||
const shouldCondense = currentOptions.whitespace !== 'preserve'
|
||||
let removedWhitespace = false
|
||||
|
|
|
@ -49,14 +49,19 @@ export const isBuiltInType = (tag: string, expected: string): boolean =>
|
|||
tag === expected || tag === hyphenate(expected)
|
||||
|
||||
export function isCoreComponent(tag: string): symbol | void {
|
||||
if (isBuiltInType(tag, 'Teleport')) {
|
||||
return TELEPORT
|
||||
} else if (isBuiltInType(tag, 'Suspense')) {
|
||||
return SUSPENSE
|
||||
} else if (isBuiltInType(tag, 'KeepAlive')) {
|
||||
return KEEP_ALIVE
|
||||
} else if (isBuiltInType(tag, 'BaseTransition')) {
|
||||
return BASE_TRANSITION
|
||||
switch (tag) {
|
||||
case 'Teleport':
|
||||
case 'teleport':
|
||||
return TELEPORT
|
||||
case 'Suspense':
|
||||
case 'suspense':
|
||||
return SUSPENSE
|
||||
case 'KeepAlive':
|
||||
case 'keep-alive':
|
||||
return KEEP_ALIVE
|
||||
case 'BaseTransition':
|
||||
case 'base-transition':
|
||||
return BASE_TRANSITION
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue