Skip to content
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

Merged
merged 9 commits into from
Aug 5, 2022

Conversation

jye-sf
Copy link
Contributor

@jye-sf jye-sf commented Aug 4, 2022

Details

WIP

Does this pull request introduce a breaking change?

  • ✅ No, it does not introduce a breaking change.

Does this pull request introduce an observable change?

  • ⚠️ Yes, it does include an observable change.

GUS work item

@@ -355,18 +310,30 @@ function parseChildren(
parse5ParentLocation: parse5.ElementLocation
): void {
const children = (parse5Utils.getTemplateContent(parse5Parent) ?? parse5Parent).childNodes;

let siblingContext: IfBlock | undefined;
Copy link
Contributor Author

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 {
Copy link
Contributor Author

@jye-sf jye-sf Aug 4, 2022

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();
Copy link
Contributor Author

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();
Copy link
Contributor Author

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) {
Copy link
Contributor Author

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:

  1. 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.
  2. 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[][] = [];
Copy link
Contributor Author

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?

Copy link
Member

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();
Copy link
Member

@jmsjtu jmsjtu Aug 5, 2022

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()?

Copy link
Contributor Author

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);
Copy link
Member

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.

@jye-sf jye-sf merged commit fe34953 into salesforce:if-else-mob Aug 5, 2022
@jye-sf jye-sf deleted the jye/if-else-parser branch August 5, 2022 22:31
jye-sf added a commit that referenced this pull request Oct 5, 2022
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants