Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 778614f

Browse files
committed
fix(compiler-vapor): track close tags during template abbreviation
1 parent 7660797 commit 778614f

3 files changed

Lines changed: 40 additions & 57 deletions

File tree

‎packages/compiler-vapor/src/transform.ts‎

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,7 @@ import {
1414
getSelfName,
1515
isVSlot,
1616
} from '@vue/compiler-dom'
17-
import {
18-
EMPTY_OBJ,
19-
NOOP,
20-
extend,
21-
isArray,
22-
isInlineTag,
23-
isString,
24-
} from '@vue/shared'
17+
import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
2518
import {
2619
type BlockIRNode,
2720
DynamicFlag,
@@ -111,13 +104,13 @@ export class TransformContext<T extends AllNode = AllNode> {
111104
// whether this node is on the rightmost path of the tree
112105
// (all ancestors are also last effective children)
113106
isOnRightmostPath: boolean = true
114-
// whether there is an inline ancestor that needs closing
115-
// (i.e. is an inline tag and not on the rightmost path)
116-
hasInlineAncestorNeedingClose: boolean = false
117107
// If an ancestor in the same template must close explicitly, descendants
118108
// with matching tags must also close so the browser doesn't consume the
119109
// ancestor close tag for the descendant.
120110
templateCloseTags: Set<string> | undefined = undefined
111+
// Inline ancestors with explicit close tags also require block descendants
112+
// in the same template to close explicitly.
113+
templateCloseBlocks: boolean = false
121114

122115
private globalId = 0
123116
private nextIdMap: Map<number, number> | null = null
@@ -329,25 +322,6 @@ export class TransformContext<T extends AllNode = AllNode> {
329322
const isLastEffectiveChild = this.isEffectivelyLastChild(index)
330323
const isOnRightmostPath = this.isOnRightmostPath && isLastEffectiveChild
331324

332-
// propagate the inline ancestor status
333-
let hasInlineAncestorNeedingClose = this.hasInlineAncestorNeedingClose
334-
if (this.node.type === NodeTypes.ELEMENT) {
335-
if (this.node.tag === 'template') {
336-
// <template> acts as a boundary ensuring its content is parsed as a fragment,
337-
// protecting inner blocks from outer inline contexts.
338-
hasInlineAncestorNeedingClose = false
339-
} else if (
340-
!hasInlineAncestorNeedingClose &&
341-
!this.isOnRightmostPath &&
342-
isInlineTag(this.node.tag)
343-
) {
344-
// Logic: if current node (parent of the node being created) is inline
345-
// AND it's not on the rightmost path, then it needs closing.
346-
// Any block child inside will need to be careful.
347-
hasInlineAncestorNeedingClose = true
348-
}
349-
}
350-
351325
return Object.assign(Object.create(TransformContext.prototype), this, {
352326
node,
353327
parent: this as any,
@@ -363,8 +337,8 @@ export class TransformContext<T extends AllNode = AllNode> {
363337
effectiveParent,
364338
isLastEffectiveChild,
365339
isOnRightmostPath,
366-
hasInlineAncestorNeedingClose,
367340
templateCloseTags: this.templateCloseTags,
341+
templateCloseBlocks: this.templateCloseBlocks,
368342
} satisfies Partial<TransformContext<T>>)
369343
}
370344

‎packages/compiler-vapor/src/transforms/transformChildren.ts‎

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
isBlockOperation,
1212
} from '../ir'
1313
import {
14-
getChildTemplateCloseTags,
14+
getChildTemplateCloseState,
1515
isInSameTemplateAsParent,
1616
shouldUseCreateElement,
1717
} from './transformElement'
@@ -28,23 +28,24 @@ export const transformChildren: NodeTransform = (node, context) => {
2828
const useCreateElement =
2929
node.type === NodeTypes.ELEMENT &&
3030
shouldUseCreateElement(node, context as TransformContext<ElementNode>)
31-
const childTemplateCloseTags =
31+
const childTemplateCloseState =
3232
!isFragment && !useCreateElement
33-
? getChildTemplateCloseTags(context as TransformContext<ElementNode>)
33+
? getChildTemplateCloseState(context as TransformContext<ElementNode>)
3434
: undefined
3535

3636
for (const [i, child] of node.children.entries()) {
3737
const childContext = context.create(child, i)
38-
childContext.templateCloseTags =
39-
childTemplateCloseTags &&
38+
const isInSameTemplate =
39+
childTemplateCloseState &&
4040
child.type === NodeTypes.ELEMENT &&
4141
child.tagType === ElementTypes.ELEMENT &&
4242
isInSameTemplateAsParent(childContext as TransformContext<ElementNode>)
43-
? childTemplateCloseTags
44-
: undefined
45-
if (isFragment || useCreateElement) {
46-
childContext.hasInlineAncestorNeedingClose = false
47-
}
43+
childContext.templateCloseTags = isInSameTemplate
44+
? childTemplateCloseState.tags
45+
: undefined
46+
childContext.templateCloseBlocks = isInSameTemplate
47+
? childTemplateCloseState.blocks
48+
: false
4849
transformNode(childContext)
4950

5051
const childDynamic = childContext.dynamic

‎packages/compiler-vapor/src/transforms/transformElement.ts‎

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
isBlockTag,
2525
isBuiltInDirective,
2626
isFormattingTag,
27+
isInlineTag,
2728
isVoidTag,
2829
makeMap,
2930
} from '@vue/shared'
@@ -161,10 +162,11 @@ function canOmitEndTag(
161162
}
162163

163164
if (
164-
context.templateCloseTags &&
165-
(context.templateCloseTags.has(node.tag) ||
166-
isAlwaysCloseTag(node.tag) ||
167-
isFormattingTag(node.tag))
165+
(context.templateCloseTags &&
166+
(context.templateCloseTags.has(node.tag) ||
167+
isAlwaysCloseTag(node.tag) ||
168+
isFormattingTag(node.tag))) ||
169+
(context.templateCloseBlocks && isBlockTag(node.tag))
168170
) {
169171
return false
170172
}
@@ -186,18 +188,17 @@ function canOmitEndTag(
186188
return context.isOnRightmostPath
187189
}
188190

189-
// For inline element containing block element, if the inline ancestor
190-
// is not on rightmost path, the block must close to avoid parsing issues
191-
if (isBlockTag(node.tag) && context.hasInlineAncestorNeedingClose) {
192-
return false
193-
}
194-
195191
return context.isLastEffectiveChild
196192
}
197193

198-
export function getChildTemplateCloseTags(
194+
interface TemplateCloseState {
195+
tags: Set<string> | undefined
196+
blocks: boolean
197+
}
198+
199+
export function getChildTemplateCloseState(
199200
context: TransformContext<ElementNode>,
200-
): Set<string> | undefined {
201+
): TemplateCloseState | undefined {
201202
const { node } = context
202203
if (
203204
node.type !== NodeTypes.ELEMENT ||
@@ -207,21 +208,28 @@ export function getChildTemplateCloseTags(
207208
return
208209
}
209210

210-
const inherited = isInSameTemplateAsParent(context)
211+
const inSameTemplateAsParent = isInSameTemplateAsParent(context)
212+
const inheritedTags = inSameTemplateAsParent
211213
? context.templateCloseTags
212214
: undefined
215+
const inheritedBlocks = inSameTemplateAsParent && context.templateCloseBlocks
213216

214217
const omitEndTag =
215218
context.root === context.effectiveParent ||
216219
canOmitEndTag(node as PlainElementNode, context)
217220

218221
if (omitEndTag || isVoidTag(node.tag)) {
219-
return inherited
222+
return inheritedTags || inheritedBlocks
223+
? { tags: inheritedTags, blocks: inheritedBlocks }
224+
: undefined
220225
}
221226

222-
const tags = new Set(inherited)
227+
const tags = new Set(inheritedTags)
223228
tags.add(node.tag)
224-
return tags
229+
return {
230+
tags,
231+
blocks: inheritedBlocks || isInlineTag(node.tag),
232+
}
225233
}
226234

227235
export function isInSameTemplateAsParent(

0 commit comments

Comments
 (0)