-
Notifications
You must be signed in to change notification settings - Fork 393
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
feat: lwc:if, lwc:elseif, and lwc:else directives #2985
Conversation
@@ -355,18 +310,30 @@ function parseChildren( | |||
parse5ParentLocation: parse5.ElementLocation | |||
): void { | |||
const children = (parse5Utils.getTemplateContent(parse5Parent) ?? parse5Parent).childNodes; | |||
|
|||
let siblingContext: IfBlock | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the loop where we iterate through the siblings of a particular node and where can keep track of any context we need from sibling to sibling.
@@ -45,6 +46,12 @@ interface ParentWrapper { | |||
current: ParentNode; | |||
} | |||
|
|||
interface Scope { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhanced the parser scope to keep track of the context we need from any previous sibling scopes + any context we need to preserve about our current scope. This is currently only used for keeping track of lwc:if, lwc:elseif, and lwc:else relationships but can be enhanced in the future if we need to keep track of more info from siblings.
@@ -355,6 +310,8 @@ function parseChildren( | |||
parse5ParentLocation: parse5.ElementLocation | |||
): void { | |||
const children = (parse5Utils.getTemplateContent(parse5Parent) ?? parse5Parent).childNodes; | |||
|
|||
ctx.beginSiblingScope(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored the sibling tracking into the context object so we shouldn't need to have manual logic here anymore.
@@ -364,12 +321,23 @@ function parseChildren( | |||
} else if (parse5Utils.isTextNode(child)) { | |||
const textNodes = parseText(ctx, child); | |||
parent.children.push(...textNodes); | |||
// Non whitespace text nodes interrupt any context we may be carrying | |||
if (textNodes.length > 0) { | |||
ctx.clearSiblingScope(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO for this block and one below with comments, we do something like ctx.visitTextNode
or ctx.visitCommentNode
and let the logic for when to clear the sibling scope live inside the context object. Any thoughts on naming?
parseIfBlock, | ||
parseElseifBlock, | ||
parseElseBlock, | ||
parseForEach, | ||
parseForOf, | ||
parseIf, | ||
]; | ||
for (const parser of parsers) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this loop, I refactored the logic that adds the node to the current scope and attaches them to the appropriate parent node to the actual parsing functions for each directive. The reasoning is twofold:
- half the directives now have "special" logic on what to do when attaching them, so it's no longer very streamlined to do it here.
- there's no longer a 1:1 mapping between Node type and parser function here, so distinguishing what to do with with a given node at this level is trickier. 2 of the 6 nodes here would need some combination of
ast.isXXXXBlock
and checking for function equality to determine what to do with them. We already have all that info readily available in the parsing functions.
@@ -66,6 +69,7 @@ export default class ParserCtx { | |||
* Each scope corresponds to the original parse5.Element node. | |||
*/ | |||
private readonly scopes: ParentNode[][] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some renaming is necessary here.
@jmsjtu I had some trouble determining what kind of scope these are supposed to be to distinguish them from siblingScope
. Would it be elementScope
? nodeScope
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This specifically stores the ForBlock
, If
, IfBlock
, ElseBlock
, Element
, Component
and Slot
.
The type that encompasses all of these is ParentNode
.
The intention of this array is to keep track of all the AST nodes that are generated from a single HTML Element.
I think elementScope
would be appropriate in this case to help distinguish it from siblingScope
.
} | ||
}); | ||
} | ||
ctx.beginSiblingScope(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be ctx.clearSiblingScope()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a memory leak waiting to happen.
): IfBlock | undefined { | ||
const ifBlockAttribute = parsedAttr.pick('lwc:if'); | ||
if (!ifBlockAttribute) { | ||
return; | ||
} | ||
|
||
const hasElseBlock = ctx.findSibling(ast.isIfBlock); | ||
const hasElseBlock = ctx.findSibling(ast.isElseBlock); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should rename findSibling
in the ctx
since there's a new sibling array, maybe we can call it something like findInCurrentScope
.
* feat: lwc:if, lwc:elseif, and lwc:else directives (#2985) * feat: refactor parser context to support new behavior for slot name tracking (#2990) * feat(template-compiler): add codegen portion for else-if directives (#2995) * fix: use Fragment VNodes for if-elseif-else children (#3047) Co-authored-by: Pierre-Marie Dartus <p.dartus@salesforce.com> Co-authored-by: James Tu <j.tu@salesforce.com>
Details
WIP
Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
GUS work item