diff --git a/packages/@lwc/errors/src/compiler/error-info/index.ts b/packages/@lwc/errors/src/compiler/error-info/index.ts
index 5fabfb2949..d8e98789bd 100644
--- a/packages/@lwc/errors/src/compiler/error-info/index.ts
+++ b/packages/@lwc/errors/src/compiler/error-info/index.ts
@@ -5,7 +5,7 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
/**
- * Next error code: 1159
+ * Next error code: 1167
*/
export * from './compiler';
diff --git a/packages/@lwc/errors/src/compiler/error-info/template-transform.ts b/packages/@lwc/errors/src/compiler/error-info/template-transform.ts
index 55c0bc3983..1b56818117 100644
--- a/packages/@lwc/errors/src/compiler/error-info/template-transform.ts
+++ b/packages/@lwc/errors/src/compiler/error-info/template-transform.ts
@@ -667,4 +667,54 @@ export const ParserDiagnostics = {
level: DiagnosticLevel.Error,
url: '',
},
+ IF_BLOCK_DIRECTIVE_SHOULD_BE_EXPRESSION: {
+ code: 1159,
+ message: 'lwc:if directive value should be an expression',
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
+ ELSEIF_BLOCK_DIRECTIVE_SHOULD_BE_EXPRESSION: {
+ code: 1160,
+ message: 'lwc:elseif directive value should be an expression',
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
+ ELSE_BLOCK_DIRECTIVE_CANNOT_HAVE_VALUE: {
+ code: 1161,
+ message: 'lwc:else directive cannot have a value',
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
+ INVALID_IF_BLOCK_DIRECTIVE_WITH_CONDITIONAL: {
+ code: 1162,
+ message: "Invalid usage of 'lwc:if' and '{0}' directives on the same element.",
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
+ INVALID_ELSEIF_BLOCK_DIRECTIVE_WITH_CONDITIONAL: {
+ code: 1163,
+ message: "Invalid usage of 'lwc:elseif' and '{0}' directives on the same element.",
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
+ INVALID_ELSE_BLOCK_DIRECTIVE_WITH_CONDITIONAL: {
+ code: 1164,
+ message: "Invalid usage of 'lwc:else' and '{0}' directives on the same element.",
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
+ LWC_IF_SCOPE_NOT_FOUND: {
+ code: 1165,
+ message:
+ "'{0}' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
+ LWC_IF_CANNOT_BE_USED_WITH_IF_DIRECTIVE: {
+ code: 1166,
+ message:
+ "'{0}' directive cannot be used with 'lwc:if', 'lwc:elseif', or 'lwc:else directives on the same element.",
+ level: DiagnosticLevel.Error,
+ url: '',
+ },
};
diff --git a/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/index.spec.js b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/index.spec.js
new file mode 100644
index 0000000000..99007ca09b
--- /dev/null
+++ b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/index.spec.js
@@ -0,0 +1,148 @@
+import { createElement } from 'lwc';
+import XComplex from 'x/complex';
+import XTest from 'x/test';
+import XForEach from 'x/forEach';
+
+describe('lwc:if, lwc:elseif, lwc:else directives', () => {
+ it('should render if branch if the value for lwc:if is truthy', () => {
+ const elm = createElement('x-test', { is: XTest });
+ elm.showIf = true;
+ document.body.appendChild(elm);
+
+ expect(elm.shadowRoot.querySelector('.if')).not.toBeNull();
+ });
+
+ it('should render elseif branch if the value for lwc:if is falsy and the value for lwc:elseif is truthy', () => {
+ const elm = createElement('x-test', { is: XTest });
+ elm.showElseif = true;
+ document.body.appendChild(elm);
+
+ expect(elm.shadowRoot.querySelector('.elseif')).not.toBeNull();
+ });
+
+ it('should render else branch if the values for lwc:if and lwc:elseif are all falsy', () => {
+ const elm = createElement('x-test', { is: XTest });
+ document.body.appendChild(elm);
+
+ expect(elm.shadowRoot.querySelector('.else')).not.toBeNull();
+ });
+
+ it('should update which branch is rendered if the value changes', () => {
+ const elm = createElement('x-test', { is: XTest });
+ elm.showIf = true;
+ document.body.appendChild(elm);
+
+ expect(elm.shadowRoot.querySelector('.if')).not.toBeNull();
+
+ elm.showIf = false;
+ return Promise.resolve()
+ .then(() => {
+ expect(elm.shadowRoot.querySelector('.else')).not.toBeNull();
+ elm.showElseif = true;
+ })
+ .then(() => {
+ expect(elm.shadowRoot.querySelector('.elseif')).not.toBeNull();
+ elm.showIf = true;
+ })
+ .then(() => {
+ expect(elm.shadowRoot.querySelector('.if')).not.toBeNull();
+ });
+ });
+
+ it('should render content when nested inside another if branch', () => {
+ const element = createElement('x-complex', { is: XComplex });
+ element.showNestedContent = true;
+ document.body.appendChild(element);
+
+ expect(element.shadowRoot.querySelector('.nestedContent')).not.toBeNull();
+ });
+
+ it('should rerender content when nested inside another if branch', () => {
+ const element = createElement('x-complex', { is: XComplex });
+ document.body.appendChild(element);
+
+ expect(element.shadowRoot.querySelector('.nestedElse')).not.toBeNull();
+
+ element.showNestedContent = true;
+ return Promise.resolve().then(() => {
+ expect(element.shadowRoot.querySelector('.nestedContent')).not.toBeNull();
+ });
+ });
+
+ it('should render list content properly', () => {
+ const element = createElement('x-complex', { is: XComplex });
+ element.showList = true;
+ document.body.appendChild(element);
+
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('123');
+ });
+
+ it('should rerender list content when updated', () => {
+ const element = createElement('x-for-each', { is: XForEach });
+ element.showList = true;
+ document.body.appendChild(element);
+
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('123');
+
+ element.appendToList({
+ value: 4,
+ show: true,
+ });
+
+ return Promise.resolve()
+ .then(() => {
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('1234');
+
+ element.showList = false;
+ element.appendToList({
+ value: 5,
+ show: true,
+ });
+ element.prependToList({
+ value: 0,
+ show: true,
+ });
+ })
+ .then(() => {
+ expect(element.shadowRoot.querySelector('.if')).toBeNull();
+
+ element.showList = true;
+ })
+ .then(() => {
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('012345');
+ });
+ });
+
+ it('should rerender list items when conditional expressions change', () => {
+ const element = createElement('x-for-each', { is: XForEach });
+ element.showList = true;
+ document.body.appendChild(element);
+
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('123');
+
+ element.appendToList({
+ value: 4,
+ show: false,
+ });
+
+ return Promise.resolve()
+ .then(() => {
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('123');
+
+ element.show(4);
+ })
+ .then(() => {
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('1234');
+
+ element.hide(1);
+ element.hide(3);
+ element.prependToList({
+ value: 0,
+ show: true,
+ });
+ })
+ .then(() => {
+ expect(element.shadowRoot.querySelector('.if').textContent).toBe('024');
+ });
+ });
+});
diff --git a/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/complex/complex.html b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/complex/complex.html
new file mode 100644
index 0000000000..8c3513b3a6
--- /dev/null
+++ b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/complex/complex.html
@@ -0,0 +1,18 @@
+
+ Header
+
+
+
+ Nested Content
+
+
+ Nothing for you
+
+
Nested Footer
+
+ Footer
+
diff --git a/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/complex/complex.js b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/complex/complex.js
new file mode 100644
index 0000000000..6cf814e641
--- /dev/null
+++ b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/complex/complex.js
@@ -0,0 +1,7 @@
+import { LightningElement, api, track } from 'lwc';
+
+export default class Complex extends LightningElement {
+ @api showNestedContent = false;
+ @api showList = false;
+ @track items = [1, 2, 3];
+}
diff --git a/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/forEach/forEach.html b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/forEach/forEach.html
new file mode 100644
index 0000000000..32272a3cbd
--- /dev/null
+++ b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/forEach/forEach.html
@@ -0,0 +1,9 @@
+
+
+
diff --git a/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/forEach/forEach.js b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/forEach/forEach.js
new file mode 100644
index 0000000000..3a995b2f2e
--- /dev/null
+++ b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/forEach/forEach.js
@@ -0,0 +1,34 @@
+import { LightningElement, api, track } from 'lwc';
+
+export default class ForEach extends LightningElement {
+ @api showList = false;
+ @track items = [
+ { value: 1, show: true },
+ { value: 2, show: true },
+ { value: 3, show: true },
+ ];
+
+ @api
+ appendToList(value) {
+ this.items.push(value);
+ }
+
+ @api
+ prependToList(value) {
+ this.items.splice(0, 0, value);
+ }
+
+ @api
+ hide(value) {
+ this.find(value).show = false;
+ }
+
+ @api
+ show(value) {
+ this.find(value).show = true;
+ }
+
+ find(value) {
+ return this.items.find((item) => item.value === value);
+ }
+}
diff --git a/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/test/test.html b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/test/test.html
new file mode 100644
index 0000000000..58c7e0d98c
--- /dev/null
+++ b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/test/test.html
@@ -0,0 +1,11 @@
+
+
+ If!
+
+
+ Else If!
+
+
+ Else!
+
+
diff --git a/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/test/test.js b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/test/test.js
new file mode 100644
index 0000000000..badbf36f7c
--- /dev/null
+++ b/packages/@lwc/integration-karma/test/template/directive-if-elseif-else/x/test/test.js
@@ -0,0 +1,6 @@
+import { LightningElement, api } from 'lwc';
+
+export default class Test extends LightningElement {
+ @api showIf = false;
+ @api showElseif = false;
+}
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/actual.html
new file mode 100644
index 0000000000..57da882db9
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/actual.html
@@ -0,0 +1,6 @@
+
+
+ Conditional Iteration
+ Else
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/ast.json
new file mode 100644
index 0000000000..7c471781f1
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/ast.json
@@ -0,0 +1,330 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 6,
+ "endColumn": 12,
+ "start": 0,
+ "end": 212,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 1,
+ "endLine": 6,
+ "endColumn": 12,
+ "start": 201,
+ "end": 212
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "ForEach",
+ "expression": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "items",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "item": {
+ "type": "Identifier",
+ "name": "item",
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 47,
+ "start": 42,
+ "end": 57
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 5,
+ "endColumn": 16,
+ "start": 15,
+ "end": 200
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 13,
+ "object": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 5,
+ "name": "item"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 6,
+ "end": 13,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 3,
+ "startColumn": 14,
+ "endLine": 3,
+ "endColumn": 35,
+ "start": 72,
+ "end": 93
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 78,
+ "start": 67,
+ "end": 136
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 14,
+ "endLine": 3,
+ "endColumn": 35,
+ "start": 72,
+ "end": 93
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 78,
+ "start": 67,
+ "end": 136,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 51,
+ "start": 67,
+ "end": 109
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 72,
+ "endLine": 3,
+ "endColumn": 78,
+ "start": 130,
+ "end": 136
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Key",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 9,
+ "object": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 5,
+ "name": "item"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 6,
+ "end": 9,
+ "name": "key"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 3,
+ "startColumn": 36,
+ "endLine": 3,
+ "endColumn": 50,
+ "start": 94,
+ "end": 108
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 36,
+ "endLine": 3,
+ "endColumn": 50,
+ "start": 94,
+ "end": 108
+ }
+ }
+ ],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Iteration",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Iteration"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 51,
+ "endLine": 3,
+ "endColumn": 72,
+ "start": 109,
+ "end": 130
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 4,
+ "endColumn": 48,
+ "start": 145,
+ "end": 184
+ },
+ "directiveLocation": {
+ "startLine": 4,
+ "startColumn": 14,
+ "endLine": 4,
+ "endColumn": 22,
+ "start": 150,
+ "end": 158
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 4,
+ "endColumn": 48,
+ "start": 145,
+ "end": 184,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 4,
+ "endColumn": 38,
+ "start": 145,
+ "end": 174
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 42,
+ "endLine": 4,
+ "endColumn": 48,
+ "start": 178,
+ "end": 184
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Key",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 9,
+ "object": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 5,
+ "name": "item"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 6,
+ "end": 9,
+ "name": "key"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 4,
+ "startColumn": 23,
+ "endLine": 4,
+ "endColumn": 37,
+ "start": 159,
+ "end": 173
+ }
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 23,
+ "endLine": 4,
+ "endColumn": 37,
+ "start": 159,
+ "end": 173
+ }
+ }
+ ],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else",
+ "value": {
+ "type": "Literal",
+ "value": "Else"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 38,
+ "endLine": 4,
+ "endColumn": 42,
+ "start": 174,
+ "end": 178
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/expected.js
new file mode 100644
index 0000000000..cad16128b5
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/expected.js
@@ -0,0 +1,42 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ k: api_key,
+ t: api_text,
+ h: api_element,
+ fr: api_fragment,
+ i: api_iterator,
+ } = $api;
+ return api_iterator($cmp.items, function (item) {
+ return item.visible
+ ? api_fragment(
+ 0,
+ [
+ api_element(
+ "div",
+ {
+ key: api_key(1, item.key),
+ },
+ [api_text("Conditional Iteration")]
+ ),
+ ],
+ 0
+ )
+ : api_fragment(
+ 0,
+ [
+ api_element(
+ "div",
+ {
+ key: api_key(2, item.key),
+ },
+ [api_text("Else")]
+ ),
+ ],
+ 0
+ );
+ });
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/html-elements/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/actual.html
new file mode 100644
index 0000000000..1ee755b7d2
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/actual.html
@@ -0,0 +1,10 @@
+
+
+
+ Conditional Iteration
+
+
+ Else
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/ast.json
new file mode 100644
index 0000000000..f075473a3e
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/ast.json
@@ -0,0 +1,330 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 10,
+ "endColumn": 12,
+ "start": 0,
+ "end": 298,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 10,
+ "startColumn": 1,
+ "endLine": 10,
+ "endColumn": 12,
+ "start": 287,
+ "end": 298
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "ForEach",
+ "expression": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "items",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "item": {
+ "type": "Identifier",
+ "name": "item",
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 47,
+ "start": 42,
+ "end": 57
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 9,
+ "endColumn": 16,
+ "start": 15,
+ "end": 286
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 13,
+ "object": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 5,
+ "name": "item"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 6,
+ "end": 13,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 3,
+ "startColumn": 19,
+ "endLine": 3,
+ "endColumn": 40,
+ "start": 77,
+ "end": 98
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 5,
+ "endColumn": 20,
+ "start": 67,
+ "end": 179
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 19,
+ "endLine": 3,
+ "endColumn": 40,
+ "start": 77,
+ "end": 98
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 4,
+ "startColumn": 13,
+ "endLine": 4,
+ "endColumn": 60,
+ "start": 112,
+ "end": 159,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 13,
+ "endLine": 4,
+ "endColumn": 33,
+ "start": 112,
+ "end": 132
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 54,
+ "endLine": 4,
+ "endColumn": 60,
+ "start": 153,
+ "end": 159
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Key",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 9,
+ "object": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 5,
+ "name": "item"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 6,
+ "end": 9,
+ "name": "key"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 4,
+ "startColumn": 18,
+ "endLine": 4,
+ "endColumn": 32,
+ "start": 117,
+ "end": 131
+ }
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 18,
+ "endLine": 4,
+ "endColumn": 32,
+ "start": 117,
+ "end": 131
+ }
+ }
+ ],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Iteration",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Iteration"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 33,
+ "endLine": 4,
+ "endColumn": 54,
+ "start": 132,
+ "end": 153
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 20,
+ "start": 188,
+ "end": 270
+ },
+ "directiveLocation": {
+ "startLine": 6,
+ "startColumn": 19,
+ "endLine": 6,
+ "endColumn": 27,
+ "start": 198,
+ "end": 206
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 43,
+ "start": 220,
+ "end": 250,
+ "startTag": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 33,
+ "start": 220,
+ "end": 240
+ },
+ "endTag": {
+ "startLine": 7,
+ "startColumn": 37,
+ "endLine": 7,
+ "endColumn": 43,
+ "start": 244,
+ "end": 250
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Key",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 9,
+ "object": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 5,
+ "name": "item"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 6,
+ "end": 9,
+ "name": "key"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 7,
+ "startColumn": 18,
+ "endLine": 7,
+ "endColumn": 32,
+ "start": 225,
+ "end": 239
+ }
+ },
+ "location": {
+ "startLine": 7,
+ "startColumn": 18,
+ "endLine": 7,
+ "endColumn": 32,
+ "start": 225,
+ "end": 239
+ }
+ }
+ ],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else",
+ "value": {
+ "type": "Literal",
+ "value": "Else"
+ },
+ "location": {
+ "startLine": 7,
+ "startColumn": 33,
+ "endLine": 7,
+ "endColumn": 37,
+ "start": 240,
+ "end": 244
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/expected.js
new file mode 100644
index 0000000000..cad16128b5
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/expected.js
@@ -0,0 +1,42 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ k: api_key,
+ t: api_text,
+ h: api_element,
+ fr: api_fragment,
+ i: api_iterator,
+ } = $api;
+ return api_iterator($cmp.items, function (item) {
+ return item.visible
+ ? api_fragment(
+ 0,
+ [
+ api_element(
+ "div",
+ {
+ key: api_key(1, item.key),
+ },
+ [api_text("Conditional Iteration")]
+ ),
+ ],
+ 0
+ )
+ : api_fragment(
+ 0,
+ [
+ api_element(
+ "div",
+ {
+ key: api_key(2, item.key),
+ },
+ [api_text("Else")]
+ ),
+ ],
+ 0
+ );
+ });
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/directive-for-each/template/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/actual.html
new file mode 100644
index 0000000000..a3d75e2fa2
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/actual.html
@@ -0,0 +1,8 @@
+
+
+ if condition
+
+
+
+
+
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/ast.json
new file mode 100644
index 0000000000..932249530f
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/ast.json
@@ -0,0 +1,244 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 8,
+ "endColumn": 12,
+ "start": 0,
+ "end": 197,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 8,
+ "startColumn": 1,
+ "endLine": 8,
+ "endColumn": 12,
+ "start": 186,
+ "end": 197
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 11,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 11,
+ "name": "if"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 91
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 54,
+ "end": 75,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 13,
+ "start": 54,
+ "end": 58
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 25,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 70,
+ "end": 75
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "if condition",
+ "value": {
+ "type": "Literal",
+ "value": "if condition"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 13,
+ "endLine": 3,
+ "endColumn": 25,
+ "start": 58,
+ "end": 70
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 5,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 16,
+ "start": 96,
+ "end": 185
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 23,
+ "start": 106,
+ "end": 114
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "x-foo",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 54,
+ "start": 124,
+ "end": 169,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 46,
+ "start": 124,
+ "end": 161
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 46,
+ "endLine": 6,
+ "endColumn": 54,
+ "start": 161,
+ "end": 169
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Dynamic",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 16,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 12,
+ "name": "trackedProp"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 13,
+ "end": 16,
+ "name": "foo"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 6,
+ "startColumn": 16,
+ "endLine": 6,
+ "endColumn": 45,
+ "start": 131,
+ "end": 160
+ }
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 16,
+ "endLine": 6,
+ "endColumn": 45,
+ "start": 131,
+ "end": 160
+ }
+ }
+ ],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/config.json
new file mode 100644
index 0000000000..7fa4e84f22
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/config.json
@@ -0,0 +1,3 @@
+{
+ "experimentalDynamicDirective": true
+}
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/expected.js
new file mode 100644
index 0000000000..ea77c14fa2
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/expected.js
@@ -0,0 +1,24 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`if condition
`;
+const stc0 = {
+ key: 3,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ st: api_static_fragment,
+ fr: api_fragment,
+ dc: api_dynamic_component,
+ } = $api;
+ return [
+ $cmp.visible.if
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : api_fragment(
+ 0,
+ [api_dynamic_component("x-foo", $cmp.trackedProp.foo, stc0)],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-else/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/actual.html
new file mode 100644
index 0000000000..9f8792a358
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/actual.html
@@ -0,0 +1,25 @@
+
+
+ outer if
+
+
+ outer elseif
+
+
+
+ inner if
+
+
+ inner elseif
+
+
+
+
+
+ inner else
+
+
+
+ outer else
+
+
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/ast.json
new file mode 100644
index 0000000000..8af00dffd0
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/ast.json
@@ -0,0 +1,805 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 25,
+ "endColumn": 12,
+ "start": 0,
+ "end": 701,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 25,
+ "startColumn": 1,
+ "endLine": 25,
+ "endColumn": 12,
+ "start": 690,
+ "end": 701
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 9,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "outer"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 7,
+ "end": 9,
+ "name": "if"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 32,
+ "start": 25,
+ "end": 42
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 85
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 32,
+ "start": 25,
+ "end": 42
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 26,
+ "start": 52,
+ "end": 69,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 13,
+ "start": 52,
+ "end": 56
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 21,
+ "endLine": 3,
+ "endColumn": 26,
+ "start": 64,
+ "end": 69
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "outer if",
+ "value": {
+ "type": "Literal",
+ "value": "outer if"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 13,
+ "endLine": 3,
+ "endColumn": 21,
+ "start": 56,
+ "end": 64
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 14,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "outer"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 7,
+ "end": 14,
+ "name": "elseif1"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 41,
+ "start": 100,
+ "end": 126
+ }
+ },
+ "location": {
+ "startLine": 5,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 16,
+ "start": 90,
+ "end": 173
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 41,
+ "start": 100,
+ "end": 126
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 30,
+ "start": 136,
+ "end": 157,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 13,
+ "start": 136,
+ "end": 140
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 25,
+ "endLine": 6,
+ "endColumn": 30,
+ "start": 152,
+ "end": 157
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "outer elseif",
+ "value": {
+ "type": "Literal",
+ "value": "outer elseif"
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 25,
+ "start": 140,
+ "end": 152
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 14,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "outer"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 7,
+ "end": 14,
+ "name": "elseif2"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 8,
+ "startColumn": 15,
+ "endLine": 8,
+ "endColumn": 41,
+ "start": 188,
+ "end": 214
+ }
+ },
+ "location": {
+ "startLine": 8,
+ "startColumn": 5,
+ "endLine": 21,
+ "endColumn": 16,
+ "start": 178,
+ "end": 621
+ },
+ "directiveLocation": {
+ "startLine": 8,
+ "startColumn": 15,
+ "endLine": 8,
+ "endColumn": 41,
+ "start": 188,
+ "end": 214
+ },
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 9,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "inner"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 7,
+ "end": 9,
+ "name": "if"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 9,
+ "startColumn": 19,
+ "endLine": 9,
+ "endColumn": 36,
+ "start": 234,
+ "end": 251
+ }
+ },
+ "location": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 11,
+ "endColumn": 20,
+ "start": 224,
+ "end": 302
+ },
+ "directiveLocation": {
+ "startLine": 9,
+ "startColumn": 19,
+ "endLine": 9,
+ "endColumn": 36,
+ "start": 234,
+ "end": 251
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 10,
+ "startColumn": 13,
+ "endLine": 10,
+ "endColumn": 30,
+ "start": 265,
+ "end": 282,
+ "startTag": {
+ "startLine": 10,
+ "startColumn": 13,
+ "endLine": 10,
+ "endColumn": 17,
+ "start": 265,
+ "end": 269
+ },
+ "endTag": {
+ "startLine": 10,
+ "startColumn": 25,
+ "endLine": 10,
+ "endColumn": 30,
+ "start": 277,
+ "end": 282
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "inner if",
+ "value": {
+ "type": "Literal",
+ "value": "inner if"
+ },
+ "location": {
+ "startLine": 10,
+ "startColumn": 17,
+ "endLine": 10,
+ "endColumn": 25,
+ "start": 269,
+ "end": 277
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 13,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "inner"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 7,
+ "end": 13,
+ "name": "elseif"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 12,
+ "startColumn": 19,
+ "endLine": 12,
+ "endColumn": 44,
+ "start": 321,
+ "end": 346
+ }
+ },
+ "location": {
+ "startLine": 12,
+ "startColumn": 9,
+ "endLine": 14,
+ "endColumn": 20,
+ "start": 311,
+ "end": 401
+ },
+ "directiveLocation": {
+ "startLine": 12,
+ "startColumn": 19,
+ "endLine": 12,
+ "endColumn": 44,
+ "start": 321,
+ "end": 346
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 13,
+ "startColumn": 13,
+ "endLine": 13,
+ "endColumn": 34,
+ "start": 360,
+ "end": 381,
+ "startTag": {
+ "startLine": 13,
+ "startColumn": 13,
+ "endLine": 13,
+ "endColumn": 17,
+ "start": 360,
+ "end": 364
+ },
+ "endTag": {
+ "startLine": 13,
+ "startColumn": 29,
+ "endLine": 13,
+ "endColumn": 34,
+ "start": 376,
+ "end": 381
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "inner elseif",
+ "value": {
+ "type": "Literal",
+ "value": "inner elseif"
+ },
+ "location": {
+ "startLine": 13,
+ "startColumn": 17,
+ "endLine": 13,
+ "endColumn": 29,
+ "start": 364,
+ "end": 376
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 14,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "inner"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 7,
+ "end": 14,
+ "name": "elseif2"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 15,
+ "startColumn": 19,
+ "endLine": 15,
+ "endColumn": 45,
+ "start": 420,
+ "end": 446
+ }
+ },
+ "location": {
+ "startLine": 15,
+ "startColumn": 9,
+ "endLine": 17,
+ "endColumn": 20,
+ "start": 410,
+ "end": 525
+ },
+ "directiveLocation": {
+ "startLine": 15,
+ "startColumn": 19,
+ "endLine": 15,
+ "endColumn": 45,
+ "start": 420,
+ "end": 446
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "x-foo",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 16,
+ "startColumn": 13,
+ "endLine": 16,
+ "endColumn": 58,
+ "start": 460,
+ "end": 505,
+ "startTag": {
+ "startLine": 16,
+ "startColumn": 13,
+ "endLine": 16,
+ "endColumn": 50,
+ "start": 460,
+ "end": 497
+ },
+ "endTag": {
+ "startLine": 16,
+ "startColumn": 50,
+ "endLine": 16,
+ "endColumn": 58,
+ "start": 497,
+ "end": 505
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Dynamic",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 16,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 12,
+ "name": "trackedProp"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 13,
+ "end": 16,
+ "name": "foo"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 16,
+ "startColumn": 20,
+ "endLine": 16,
+ "endColumn": 49,
+ "start": 467,
+ "end": 496
+ }
+ },
+ "location": {
+ "startLine": 16,
+ "startColumn": 20,
+ "endLine": 16,
+ "endColumn": 49,
+ "start": 467,
+ "end": 496
+ }
+ }
+ ],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 18,
+ "startColumn": 9,
+ "endLine": 20,
+ "endColumn": 20,
+ "start": 534,
+ "end": 605
+ },
+ "directiveLocation": {
+ "startLine": 18,
+ "startColumn": 19,
+ "endLine": 18,
+ "endColumn": 27,
+ "start": 544,
+ "end": 552
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 19,
+ "startColumn": 13,
+ "endLine": 19,
+ "endColumn": 32,
+ "start": 566,
+ "end": 585,
+ "startTag": {
+ "startLine": 19,
+ "startColumn": 13,
+ "endLine": 19,
+ "endColumn": 17,
+ "start": 566,
+ "end": 570
+ },
+ "endTag": {
+ "startLine": 19,
+ "startColumn": 27,
+ "endLine": 19,
+ "endColumn": 32,
+ "start": 580,
+ "end": 585
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "inner else",
+ "value": {
+ "type": "Literal",
+ "value": "inner else"
+ },
+ "location": {
+ "startLine": 19,
+ "startColumn": 17,
+ "endLine": 19,
+ "endColumn": 27,
+ "start": 570,
+ "end": 580
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 22,
+ "startColumn": 5,
+ "endLine": 24,
+ "endColumn": 16,
+ "start": 626,
+ "end": 689
+ },
+ "directiveLocation": {
+ "startLine": 22,
+ "startColumn": 15,
+ "endLine": 22,
+ "endColumn": 23,
+ "start": 636,
+ "end": 644
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 23,
+ "startColumn": 9,
+ "endLine": 23,
+ "endColumn": 28,
+ "start": 654,
+ "end": 673,
+ "startTag": {
+ "startLine": 23,
+ "startColumn": 9,
+ "endLine": 23,
+ "endColumn": 13,
+ "start": 654,
+ "end": 658
+ },
+ "endTag": {
+ "startLine": 23,
+ "startColumn": 23,
+ "endLine": 23,
+ "endColumn": 28,
+ "start": 668,
+ "end": 673
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "outer else",
+ "value": {
+ "type": "Literal",
+ "value": "outer else"
+ },
+ "location": {
+ "startLine": 23,
+ "startColumn": 13,
+ "endLine": 23,
+ "endColumn": 23,
+ "start": 658,
+ "end": 668
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/config.json
new file mode 100644
index 0000000000..7fa4e84f22
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/config.json
@@ -0,0 +1,3 @@
+{
+ "experimentalDynamicDirective": true
+}
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/expected.js
new file mode 100644
index 0000000000..7419f0a850
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/expected.js
@@ -0,0 +1,45 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`outer if
`;
+const $fragment2 = parseFragment`outer elseif
`;
+const $fragment3 = parseFragment`inner if
`;
+const $fragment4 = parseFragment`inner elseif
`;
+const $fragment5 = parseFragment`inner else
`;
+const $fragment6 = parseFragment`outer else
`;
+const stc0 = {
+ key: 10,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ st: api_static_fragment,
+ fr: api_fragment,
+ dc: api_dynamic_component,
+ } = $api;
+ return [
+ $cmp.outer.if
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : $cmp.outer.elseif1
+ ? api_fragment(0, [api_static_fragment($fragment2(), 4)], 0)
+ : $cmp.outer.elseif2
+ ? api_fragment(
+ 0,
+ [
+ $cmp.inner.if
+ ? api_fragment(5, [api_static_fragment($fragment3(), 7)], 0)
+ : $cmp.inner.elseif
+ ? api_fragment(5, [api_static_fragment($fragment4(), 9)], 0)
+ : $cmp.inner.elseif2
+ ? api_fragment(
+ 5,
+ [api_dynamic_component("x-foo", $cmp.trackedProp.foo, stc0)],
+ 0
+ )
+ : api_fragment(5, [api_static_fragment($fragment5(), 12)], 0),
+ ],
+ 0
+ )
+ : api_fragment(0, [api_static_fragment($fragment6(), 14)], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else-nested/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/actual.html
new file mode 100644
index 0000000000..224e213de0
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/actual.html
@@ -0,0 +1,11 @@
+
+
+ if condition
+
+
+ elseif condition
+
+
+
+
+
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/ast.json
new file mode 100644
index 0000000000..ef7116dd1e
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/ast.json
@@ -0,0 +1,352 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 11,
+ "endColumn": 12,
+ "start": 0,
+ "end": 290,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 11,
+ "startColumn": 1,
+ "endLine": 11,
+ "endColumn": 12,
+ "start": 279,
+ "end": 290
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 11,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 11,
+ "name": "if"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 91
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 54,
+ "end": 75,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 13,
+ "start": 54,
+ "end": 58
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 25,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 70,
+ "end": 75
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "if condition",
+ "value": {
+ "type": "Literal",
+ "value": "if condition"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 13,
+ "endLine": 3,
+ "endColumn": 25,
+ "start": 58,
+ "end": 70
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 15,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 15,
+ "name": "elseif"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 42,
+ "start": 106,
+ "end": 133
+ }
+ },
+ "location": {
+ "startLine": 5,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 16,
+ "start": 96,
+ "end": 184
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 42,
+ "start": 106,
+ "end": 133
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 34,
+ "start": 143,
+ "end": 168,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 13,
+ "start": 143,
+ "end": 147
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 29,
+ "endLine": 6,
+ "endColumn": 34,
+ "start": 163,
+ "end": 168
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "elseif condition",
+ "value": {
+ "type": "Literal",
+ "value": "elseif condition"
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 29,
+ "start": 147,
+ "end": 163
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 8,
+ "startColumn": 5,
+ "endLine": 10,
+ "endColumn": 16,
+ "start": 189,
+ "end": 278
+ },
+ "directiveLocation": {
+ "startLine": 8,
+ "startColumn": 15,
+ "endLine": 8,
+ "endColumn": 23,
+ "start": 199,
+ "end": 207
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "x-foo",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 54,
+ "start": 217,
+ "end": 262,
+ "startTag": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 46,
+ "start": 217,
+ "end": 254
+ },
+ "endTag": {
+ "startLine": 9,
+ "startColumn": 46,
+ "endLine": 9,
+ "endColumn": 54,
+ "start": 254,
+ "end": 262
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Dynamic",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 16,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 12,
+ "name": "trackedProp"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 13,
+ "end": 16,
+ "name": "foo"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 9,
+ "startColumn": 16,
+ "endLine": 9,
+ "endColumn": 45,
+ "start": 224,
+ "end": 253
+ }
+ },
+ "location": {
+ "startLine": 9,
+ "startColumn": 16,
+ "endLine": 9,
+ "endColumn": 45,
+ "start": 224,
+ "end": 253
+ }
+ }
+ ],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/config.json
new file mode 100644
index 0000000000..7fa4e84f22
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/config.json
@@ -0,0 +1,3 @@
+{
+ "experimentalDynamicDirective": true
+}
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/expected.js
new file mode 100644
index 0000000000..f7072d9d04
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/expected.js
@@ -0,0 +1,27 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`if condition
`;
+const $fragment2 = parseFragment`elseif condition
`;
+const stc0 = {
+ key: 5,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ st: api_static_fragment,
+ fr: api_fragment,
+ dc: api_dynamic_component,
+ } = $api;
+ return [
+ $cmp.visible.if
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : $cmp.visible.elseif
+ ? api_fragment(0, [api_static_fragment($fragment2(), 4)], 0)
+ : api_fragment(
+ 0,
+ [api_dynamic_component("x-foo", $cmp.trackedProp.foo, stc0)],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-else/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/actual.html
new file mode 100644
index 0000000000..b53d706472
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/actual.html
@@ -0,0 +1,14 @@
+
+
+ if condition
+
+
+ elseif condition
+
+
+
+
+
+ else condition
+
+
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/ast.json
new file mode 100644
index 0000000000..4298b72df6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/ast.json
@@ -0,0 +1,460 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 14,
+ "endColumn": 12,
+ "start": 0,
+ "end": 382,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 14,
+ "startColumn": 1,
+ "endLine": 14,
+ "endColumn": 12,
+ "start": 371,
+ "end": 382
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 11,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 11,
+ "name": "if"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 91
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 54,
+ "end": 75,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 13,
+ "start": 54,
+ "end": 58
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 25,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 70,
+ "end": 75
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "if condition",
+ "value": {
+ "type": "Literal",
+ "value": "if condition"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 13,
+ "endLine": 3,
+ "endColumn": 25,
+ "start": 58,
+ "end": 70
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 15,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 15,
+ "name": "elseif"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 42,
+ "start": 106,
+ "end": 133
+ }
+ },
+ "location": {
+ "startLine": 5,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 16,
+ "start": 96,
+ "end": 184
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 42,
+ "start": 106,
+ "end": 133
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 34,
+ "start": 143,
+ "end": 168,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 13,
+ "start": 143,
+ "end": 147
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 29,
+ "endLine": 6,
+ "endColumn": 34,
+ "start": 163,
+ "end": 168
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "elseif condition",
+ "value": {
+ "type": "Literal",
+ "value": "elseif condition"
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 29,
+ "start": 147,
+ "end": 163
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 16,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 16,
+ "name": "elseif2"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 8,
+ "startColumn": 15,
+ "endLine": 8,
+ "endColumn": 43,
+ "start": 199,
+ "end": 227
+ }
+ },
+ "location": {
+ "startLine": 8,
+ "startColumn": 5,
+ "endLine": 10,
+ "endColumn": 16,
+ "start": 189,
+ "end": 298
+ },
+ "directiveLocation": {
+ "startLine": 8,
+ "startColumn": 15,
+ "endLine": 8,
+ "endColumn": 43,
+ "start": 199,
+ "end": 227
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "x-foo",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 54,
+ "start": 237,
+ "end": 282,
+ "startTag": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 46,
+ "start": 237,
+ "end": 274
+ },
+ "endTag": {
+ "startLine": 9,
+ "startColumn": 46,
+ "endLine": 9,
+ "endColumn": 54,
+ "start": 274,
+ "end": 282
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Dynamic",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 16,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 12,
+ "name": "trackedProp"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 13,
+ "end": 16,
+ "name": "foo"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 9,
+ "startColumn": 16,
+ "endLine": 9,
+ "endColumn": 45,
+ "start": 244,
+ "end": 273
+ }
+ },
+ "location": {
+ "startLine": 9,
+ "startColumn": 16,
+ "endLine": 9,
+ "endColumn": 45,
+ "start": 244,
+ "end": 273
+ }
+ }
+ ],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 11,
+ "startColumn": 5,
+ "endLine": 13,
+ "endColumn": 16,
+ "start": 303,
+ "end": 370
+ },
+ "directiveLocation": {
+ "startLine": 11,
+ "startColumn": 15,
+ "endLine": 11,
+ "endColumn": 23,
+ "start": 313,
+ "end": 321
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 12,
+ "startColumn": 9,
+ "endLine": 12,
+ "endColumn": 32,
+ "start": 331,
+ "end": 354,
+ "startTag": {
+ "startLine": 12,
+ "startColumn": 9,
+ "endLine": 12,
+ "endColumn": 13,
+ "start": 331,
+ "end": 335
+ },
+ "endTag": {
+ "startLine": 12,
+ "startColumn": 27,
+ "endLine": 12,
+ "endColumn": 32,
+ "start": 349,
+ "end": 354
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "else condition",
+ "value": {
+ "type": "Literal",
+ "value": "else condition"
+ },
+ "location": {
+ "startLine": 12,
+ "startColumn": 13,
+ "endLine": 12,
+ "endColumn": 27,
+ "start": 335,
+ "end": 349
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/config.json
new file mode 100644
index 0000000000..7fa4e84f22
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/config.json
@@ -0,0 +1,3 @@
+{
+ "experimentalDynamicDirective": true
+}
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/expected.js
new file mode 100644
index 0000000000..18fc0112f3
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/expected.js
@@ -0,0 +1,30 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`if condition
`;
+const $fragment2 = parseFragment`elseif condition
`;
+const $fragment3 = parseFragment`else condition
`;
+const stc0 = {
+ key: 5,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ st: api_static_fragment,
+ fr: api_fragment,
+ dc: api_dynamic_component,
+ } = $api;
+ return [
+ $cmp.visible.if
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : $cmp.visible.elseif
+ ? api_fragment(0, [api_static_fragment($fragment2(), 4)], 0)
+ : $cmp.visible.elseif2
+ ? api_fragment(
+ 0,
+ [api_dynamic_component("x-foo", $cmp.trackedProp.foo, stc0)],
+ 0
+ )
+ : api_fragment(0, [api_static_fragment($fragment3(), 7)], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif-multiple/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/actual.html
new file mode 100644
index 0000000000..c55738e583
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/actual.html
@@ -0,0 +1,8 @@
+
+
+ if condition
+
+
+
+
+
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/ast.json
new file mode 100644
index 0000000000..033b6e1815
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/ast.json
@@ -0,0 +1,280 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 8,
+ "endColumn": 12,
+ "start": 0,
+ "end": 216,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 8,
+ "startColumn": 1,
+ "endLine": 8,
+ "endColumn": 12,
+ "start": 205,
+ "end": 216
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 11,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 11,
+ "name": "if"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 91
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 54,
+ "end": 75,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 13,
+ "start": 54,
+ "end": 58
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 25,
+ "endLine": 3,
+ "endColumn": 30,
+ "start": 70,
+ "end": 75
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "if condition",
+ "value": {
+ "type": "Literal",
+ "value": "if condition"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 13,
+ "endLine": 3,
+ "endColumn": 25,
+ "start": 58,
+ "end": 70
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 15,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 15,
+ "name": "elseif"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 42,
+ "start": 106,
+ "end": 133
+ }
+ },
+ "location": {
+ "startLine": 5,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 16,
+ "start": 96,
+ "end": 204
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 42,
+ "start": 106,
+ "end": 133
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "x-foo",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 54,
+ "start": 143,
+ "end": 188,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 46,
+ "start": 143,
+ "end": 180
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 46,
+ "endLine": 6,
+ "endColumn": 54,
+ "start": 180,
+ "end": 188
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Dynamic",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 16,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 12,
+ "name": "trackedProp"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 13,
+ "end": 16,
+ "name": "foo"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 6,
+ "startColumn": 16,
+ "endLine": 6,
+ "endColumn": 45,
+ "start": 150,
+ "end": 179
+ }
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 16,
+ "endLine": 6,
+ "endColumn": 45,
+ "start": 150,
+ "end": 179
+ }
+ }
+ ],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/config.json
new file mode 100644
index 0000000000..7fa4e84f22
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/config.json
@@ -0,0 +1,3 @@
+{
+ "experimentalDynamicDirective": true
+}
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/expected.js
new file mode 100644
index 0000000000..7a836a714b
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/expected.js
@@ -0,0 +1,26 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`if condition
`;
+const stc0 = {
+ key: 3,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ st: api_static_fragment,
+ fr: api_fragment,
+ dc: api_dynamic_component,
+ } = $api;
+ return [
+ $cmp.visible.if
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : $cmp.visible.elseif
+ ? api_fragment(
+ 0,
+ [api_dynamic_component("x-foo", $cmp.trackedProp.foo, stc0)],
+ 0
+ )
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if-elseif/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/actual.html
new file mode 100644
index 0000000000..761702d104
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/actual.html
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/ast.json
new file mode 100644
index 0000000000..9f08e37b1d
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/ast.json
@@ -0,0 +1,172 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 0,
+ "end": 127,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 116,
+ "end": 127
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 11,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 9,
+ "end": 11,
+ "name": "if"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 115
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 34,
+ "start": 25,
+ "end": 44
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "x-foo",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 54,
+ "start": 54,
+ "end": 99,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 46,
+ "start": 54,
+ "end": 91
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 46,
+ "endLine": 3,
+ "endColumn": 54,
+ "start": 91,
+ "end": 99
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [
+ {
+ "type": "Directive",
+ "name": "Dynamic",
+ "value": {
+ "type": "MemberExpression",
+ "start": 1,
+ "end": 16,
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "$cmp"
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 12,
+ "name": "trackedProp"
+ },
+ "computed": false,
+ "optional": false
+ },
+ "property": {
+ "type": "Identifier",
+ "start": 13,
+ "end": 16,
+ "name": "foo"
+ },
+ "computed": false,
+ "optional": false,
+ "location": {
+ "startLine": 3,
+ "startColumn": 16,
+ "endLine": 3,
+ "endColumn": 45,
+ "start": 61,
+ "end": 90
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 16,
+ "endLine": 3,
+ "endColumn": 45,
+ "start": 61,
+ "end": 90
+ }
+ }
+ ],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/config.json
new file mode 100644
index 0000000000..7fa4e84f22
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/config.json
@@ -0,0 +1,3 @@
+{
+ "experimentalDynamicDirective": true
+}
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/expected.js
new file mode 100644
index 0000000000..80d1b73935
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/expected.js
@@ -0,0 +1,19 @@
+import { registerTemplate } from "lwc";
+const stc0 = {
+ key: 1,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { dc: api_dynamic_component, fr: api_fragment } = $api;
+ return [
+ $cmp.visible.if
+ ? api_fragment(
+ 0,
+ [api_dynamic_component("x-foo", $cmp.trackedProp.foo, stc0)],
+ 0
+ )
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/dynamic/if/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/actual.html
new file mode 100644
index 0000000000..a841b54b0e
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/actual.html
@@ -0,0 +1,4 @@
+
+ Conditional Text
+ Invalid Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/metadata.json
new file mode 100644
index 0000000000..75d50952e0
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-expression/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1161,
+ "message": "LWC1161: lwc:else directive cannot have a value",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 74,
+ "length": 61
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/actual.html
new file mode 100644
index 0000000000..d8baa61e30
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/actual.html
@@ -0,0 +1,5 @@
+
+ If!
+ Header Text
+ Elseif!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/metadata.json
new file mode 100644
index 0000000000..c7214a199f
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/cannot-be-preceeded-by-text-node/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1165,
+ "message": "LWC1165: 'lwc:elseif' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ "level": 1,
+ "location": {
+ "line": 4,
+ "column": 5,
+ "start": 77,
+ "length": 48
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/actual.html
new file mode 100644
index 0000000000..d7790d99cb
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/actual.html
@@ -0,0 +1,5 @@
+
+ If!
+
+ Elseif!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/metadata.json
new file mode 100644
index 0000000000..c7214a199f
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else-if/must-be-preceeded-by-if-or-elseif/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1165,
+ "message": "LWC1165: 'lwc:elseif' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ "level": 1,
+ "location": {
+ "line": 4,
+ "column": 5,
+ "start": 77,
+ "length": 48
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/actual.html
new file mode 100644
index 0000000000..77f58374e3
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/actual.html
@@ -0,0 +1,5 @@
+
+ If!
+ Header Text
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/metadata.json
new file mode 100644
index 0000000000..2881eb52d0
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/cannot-be-preceeded-by-text-node/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1165,
+ "message": "LWC1165: 'lwc:else' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ "level": 1,
+ "location": {
+ "line": 4,
+ "column": 5,
+ "start": 77,
+ "length": 35
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/actual.html
new file mode 100644
index 0000000000..cd87ceb46d
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/actual.html
@@ -0,0 +1,5 @@
+
+ If!
+
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/metadata.json
new file mode 100644
index 0000000000..2881eb52d0
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-sibling/else/must-be-preceeded-by-if-or-elseif/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1165,
+ "message": "LWC1165: 'lwc:else' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ "level": 1,
+ "location": {
+ "line": 4,
+ "column": 5,
+ "start": 77,
+ "length": 35
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/actual.html
new file mode 100644
index 0000000000..c3067ff388
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/actual.html
@@ -0,0 +1,4 @@
+
+ Conditional Text
+ Invalid Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/metadata.json
new file mode 100644
index 0000000000..917d9c1a12
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-invalid-string-value/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1161,
+ "message": "LWC1161: lwc:else directive cannot have a value",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 74,
+ "length": 52
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/actual.html
new file mode 100644
index 0000000000..5532ab5212
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/actual.html
@@ -0,0 +1,4 @@
+
+
+ Conditional Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/metadata.json
new file mode 100644
index 0000000000..14ca8b7858
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/elseif-else/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1163,
+ "message": "LWC1163: Invalid usage of 'lwc:elseif' and 'lwc:else' directives on the same element.",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 58,
+ "length": 67
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/actual.html
new file mode 100644
index 0000000000..018bd16dab
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/actual.html
@@ -0,0 +1,3 @@
+
+ Conditional Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/metadata.json
new file mode 100644
index 0000000000..770be82ba9
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-else/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1162,
+ "message": "LWC1162: Invalid usage of 'lwc:if' and 'lwc:else' directives on the same element.",
+ "level": 1,
+ "location": {
+ "line": 2,
+ "column": 5,
+ "start": 15,
+ "length": 63
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/actual.html
new file mode 100644
index 0000000000..a8db9f820c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/actual.html
@@ -0,0 +1,3 @@
+
+ Conditional Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/metadata.json
new file mode 100644
index 0000000000..c351d99ab2
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/error-multiple-directives/if-elseif/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1162,
+ "message": "LWC1162: Invalid usage of 'lwc:if' and 'lwc:elseif' directives on the same element.",
+ "level": 1,
+ "location": {
+ "line": 2,
+ "column": 5,
+ "start": 15,
+ "length": 74
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/actual.html
new file mode 100644
index 0000000000..20bdd01ded
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/actual.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/ast.json
new file mode 100644
index 0000000000..3473cb0eab
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/ast.json
@@ -0,0 +1,156 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 0,
+ "end": 108,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 97,
+ "end": 108
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 32,
+ "start": 15,
+ "end": 42
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 42,
+ "end": 53
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 43,
+ "start": 58,
+ "end": 96
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 19,
+ "endLine": 3,
+ "endColumn": 27,
+ "start": 72,
+ "end": 80
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom-alt",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 43,
+ "start": 58,
+ "end": 96,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 28,
+ "start": 58,
+ "end": 81
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 28,
+ "endLine": 3,
+ "endColumn": 43,
+ "start": 81,
+ "end": 96
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/expected.js
new file mode 100644
index 0000000000..db6e215850
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/expected.js
@@ -0,0 +1,24 @@
+import _cCustom from "c/custom";
+import _cCustomAlt from "c/customAlt";
+import { registerTemplate } from "lwc";
+const stc0 = {
+ key: 1,
+};
+const stc1 = {
+ key: 2,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { c: api_custom_element, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_custom_element("c-custom", _cCustom, stc0)], 0)
+ : api_fragment(
+ 0,
+ [api_custom_element("c-custom-alt", _cCustomAlt, stc1)],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/components/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/actual.html
new file mode 100644
index 0000000000..0785fefedd
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/actual.html
@@ -0,0 +1,4 @@
+
+ Visible Header
+ Alternative Header
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/ast.json
new file mode 100644
index 0000000000..130c56ea1b
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/ast.json
@@ -0,0 +1,190 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 0,
+ "end": 108,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 97,
+ "end": 108
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 15,
+ "end": 55
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 15,
+ "end": 55,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 26,
+ "start": 15,
+ "end": 36
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 40,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 50,
+ "end": 55
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Visible Header",
+ "value": {
+ "type": "Literal",
+ "value": "Visible Header"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 26,
+ "endLine": 2,
+ "endColumn": 40,
+ "start": 36,
+ "end": 50
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 60,
+ "end": 96
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 17,
+ "start": 64,
+ "end": 72
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 60,
+ "end": 96,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 18,
+ "start": 60,
+ "end": 73
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 36,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 91,
+ "end": 96
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Alternative Header",
+ "value": {
+ "type": "Literal",
+ "value": "Alternative Header"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 18,
+ "endLine": 3,
+ "endColumn": 36,
+ "start": 73,
+ "end": 91
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/expected.js
new file mode 100644
index 0000000000..857cece0b6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/expected.js
@@ -0,0 +1,14 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`Visible Header
`;
+const $fragment2 = parseFragment`Alternative Header
`;
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { st: api_static_fragment, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : api_fragment(0, [api_static_fragment($fragment2(), 4)], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/html-elements/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/actual.html
new file mode 100644
index 0000000000..5a15098e30
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/actual.html
@@ -0,0 +1,4 @@
+
+ Conditional Text
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/ast.json
new file mode 100644
index 0000000000..a321123021
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/ast.json
@@ -0,0 +1,120 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 0,
+ "end": 121,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 110,
+ "end": 121
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 59,
+ "start": 15,
+ "end": 69
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 48,
+ "start": 42,
+ "end": 58
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 40,
+ "start": 74,
+ "end": 109
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 23,
+ "start": 84,
+ "end": 92
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else!",
+ "value": {
+ "type": "Literal",
+ "value": "Else!"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 24,
+ "endLine": 3,
+ "endColumn": 29,
+ "start": 93,
+ "end": 98
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/expected.js
new file mode 100644
index 0000000000..2be1cdb2ee
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/expected.js
@@ -0,0 +1,12 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_text("Conditional Text")], 0)
+ : api_fragment(0, [api_text("Else!")], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-else/template/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/actual.html
new file mode 100644
index 0000000000..23a7d137d3
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/actual.html
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/ast.json
new file mode 100644
index 0000000000..7b1b95f345
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/ast.json
@@ -0,0 +1,225 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 0,
+ "end": 170,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 159,
+ "end": 170
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 32,
+ "start": 15,
+ "end": 42
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 42,
+ "end": 53
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 7,
+ "name": "elseif",
+ "location": {
+ "startLine": 3,
+ "startColumn": 22,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 75,
+ "end": 94
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 60,
+ "start": 58,
+ "end": 113
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 22,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 75,
+ "end": 94
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom-elseif",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 60,
+ "start": 58,
+ "end": 113,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 42,
+ "start": 58,
+ "end": 95
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 42,
+ "endLine": 3,
+ "endColumn": 60,
+ "start": 95,
+ "end": 113
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 45,
+ "start": 118,
+ "end": 158
+ },
+ "directiveLocation": {
+ "startLine": 4,
+ "startColumn": 20,
+ "endLine": 4,
+ "endColumn": 28,
+ "start": 133,
+ "end": 141
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom-else",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 45,
+ "start": 118,
+ "end": 158,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 29,
+ "start": 118,
+ "end": 142
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 29,
+ "endLine": 4,
+ "endColumn": 45,
+ "start": 142,
+ "end": 158
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/expected.js
new file mode 100644
index 0000000000..0d98ae9256
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/expected.js
@@ -0,0 +1,34 @@
+import _cCustom from "c/custom";
+import _cCustomElseif from "c/customElseif";
+import _cCustomElse from "c/customElse";
+import { registerTemplate } from "lwc";
+const stc0 = {
+ key: 1,
+};
+const stc1 = {
+ key: 2,
+};
+const stc2 = {
+ key: 3,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { c: api_custom_element, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_custom_element("c-custom", _cCustom, stc0)], 0)
+ : $cmp.elseif
+ ? api_fragment(
+ 0,
+ [api_custom_element("c-custom-elseif", _cCustomElseif, stc1)],
+ 0
+ )
+ : api_fragment(
+ 0,
+ [api_custom_element("c-custom-else", _cCustomElse, stc2)],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/components/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/actual.html
new file mode 100644
index 0000000000..599bb00658
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/actual.html
@@ -0,0 +1,5 @@
+
+ Visible Header
+ First Alternative Header
+ Alternative Header
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/ast.json
new file mode 100644
index 0000000000..abbe494253
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/ast.json
@@ -0,0 +1,276 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 0,
+ "end": 175,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 164,
+ "end": 175
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 15,
+ "end": 55
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 15,
+ "end": 55,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 26,
+ "start": 15,
+ "end": 36
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 40,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 50,
+ "end": 55
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Visible Header",
+ "value": {
+ "type": "Literal",
+ "value": "Visible Header"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 26,
+ "endLine": 2,
+ "endColumn": 40,
+ "start": 36,
+ "end": 50
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 16,
+ "name": "elseifCondition",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 37,
+ "start": 64,
+ "end": 92
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 67,
+ "start": 60,
+ "end": 122
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 37,
+ "start": 64,
+ "end": 92
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 67,
+ "start": 60,
+ "end": 122,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 38,
+ "start": 60,
+ "end": 93
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 62,
+ "endLine": 3,
+ "endColumn": 67,
+ "start": 117,
+ "end": 122
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "First Alternative Header",
+ "value": {
+ "type": "Literal",
+ "value": "First Alternative Header"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 38,
+ "endLine": 3,
+ "endColumn": 62,
+ "start": 93,
+ "end": 117
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 41,
+ "start": 127,
+ "end": 163
+ },
+ "directiveLocation": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 4,
+ "endColumn": 17,
+ "start": 131,
+ "end": 139
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 41,
+ "start": 127,
+ "end": 163,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 18,
+ "start": 127,
+ "end": 140
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 36,
+ "endLine": 4,
+ "endColumn": 41,
+ "start": 158,
+ "end": 163
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Alternative Header",
+ "value": {
+ "type": "Literal",
+ "value": "Alternative Header"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 18,
+ "endLine": 4,
+ "endColumn": 36,
+ "start": 140,
+ "end": 158
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/expected.js
new file mode 100644
index 0000000000..5d514421fb
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/expected.js
@@ -0,0 +1,17 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`Visible Header
`;
+const $fragment2 = parseFragment`First Alternative Header
`;
+const $fragment3 = parseFragment`Alternative Header
`;
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { st: api_static_fragment, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : $cmp.elseifCondition
+ ? api_fragment(0, [api_static_fragment($fragment2(), 4)], 0)
+ : api_fragment(0, [api_static_fragment($fragment3(), 6)], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/html-elements/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/actual.html
new file mode 100644
index 0000000000..954d7814a6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/actual.html
@@ -0,0 +1,5 @@
+
+ Conditional Text
+ Elseif!
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/ast.json
new file mode 100644
index 0000000000..08744352c2
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/ast.json
@@ -0,0 +1,171 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 0,
+ "end": 183,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 172,
+ "end": 183
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 59,
+ "start": 15,
+ "end": 69
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 48,
+ "start": 42,
+ "end": 58
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 16,
+ "name": "elseifCondition",
+ "location": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 43,
+ "start": 84,
+ "end": 112
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 62,
+ "start": 74,
+ "end": 131
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 43,
+ "start": 84,
+ "end": 112
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Elseif!",
+ "value": {
+ "type": "Literal",
+ "value": "Elseif!"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 44,
+ "endLine": 3,
+ "endColumn": 51,
+ "start": 113,
+ "end": 120
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 40,
+ "start": 136,
+ "end": 171
+ },
+ "directiveLocation": {
+ "startLine": 4,
+ "startColumn": 15,
+ "endLine": 4,
+ "endColumn": 23,
+ "start": 146,
+ "end": 154
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else!",
+ "value": {
+ "type": "Literal",
+ "value": "Else!"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 24,
+ "endLine": 4,
+ "endColumn": 29,
+ "start": 155,
+ "end": 160
+ }
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/expected.js
new file mode 100644
index 0000000000..17662b347b
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/expected.js
@@ -0,0 +1,14 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_text("Conditional Text")], 0)
+ : $cmp.elseifCondition
+ ? api_fragment(0, [api_text("Elseif!")], 0)
+ : api_fragment(0, [api_text("Else!")], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif-else/template/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/actual.html
new file mode 100644
index 0000000000..e2fadf6925
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/actual.html
@@ -0,0 +1,4 @@
+
+ Visible Header
+ First Alternative Header
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/ast.json
new file mode 100644
index 0000000000..22cc0fff54
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/ast.json
@@ -0,0 +1,204 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 0,
+ "end": 158,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 147,
+ "end": 158
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 57,
+ "start": 15,
+ "end": 67
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 57,
+ "start": 15,
+ "end": 67,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 32,
+ "start": 15,
+ "end": 42
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 46,
+ "endLine": 2,
+ "endColumn": 57,
+ "start": 56,
+ "end": 67
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Visible Header",
+ "value": {
+ "type": "Literal",
+ "value": "Visible Header"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 46,
+ "start": 42,
+ "end": 56
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 16,
+ "name": "elseifCondition",
+ "location": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 43,
+ "start": 82,
+ "end": 110
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 79,
+ "start": 72,
+ "end": 146
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 43,
+ "start": 82,
+ "end": 110
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 79,
+ "start": 72,
+ "end": 146,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 44,
+ "start": 72,
+ "end": 111
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 68,
+ "endLine": 3,
+ "endColumn": 79,
+ "start": 135,
+ "end": 146
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "First Alternative Header",
+ "value": {
+ "type": "Literal",
+ "value": "First Alternative Header"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 44,
+ "endLine": 3,
+ "endColumn": 68,
+ "start": 111,
+ "end": 135
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/expected.js
new file mode 100644
index 0000000000..1ffb4be08e
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/expected.js
@@ -0,0 +1,37 @@
+import _cCustom from "c/custom";
+import { registerTemplate } from "lwc";
+const stc0 = {
+ key: 1,
+};
+const stc1 = {
+ key: 2,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, c: api_custom_element, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(
+ 0,
+ [
+ api_custom_element("c-custom", _cCustom, stc0, [
+ api_text("Visible Header"),
+ ]),
+ ],
+ 0
+ )
+ : $cmp.elseifCondition
+ ? api_fragment(
+ 0,
+ [
+ api_custom_element("c-custom", _cCustom, stc1, [
+ api_text("First Alternative Header"),
+ ]),
+ ],
+ 0
+ )
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/components/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/actual.html
new file mode 100644
index 0000000000..4da4d5a9b9
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/actual.html
@@ -0,0 +1,4 @@
+
+ Visible Header
+ First Alternative Header
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/ast.json
new file mode 100644
index 0000000000..d5631d5922
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/ast.json
@@ -0,0 +1,204 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 0,
+ "end": 134,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 123,
+ "end": 134
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 15,
+ "end": 55
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 15,
+ "end": 55,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 26,
+ "start": 15,
+ "end": 36
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 40,
+ "endLine": 2,
+ "endColumn": 45,
+ "start": 50,
+ "end": 55
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Visible Header",
+ "value": {
+ "type": "Literal",
+ "value": "Visible Header"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 26,
+ "endLine": 2,
+ "endColumn": 40,
+ "start": 36,
+ "end": 50
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 16,
+ "name": "elseifCondition",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 37,
+ "start": 64,
+ "end": 92
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 67,
+ "start": 60,
+ "end": 122
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 37,
+ "start": 64,
+ "end": 92
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 67,
+ "start": 60,
+ "end": 122,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 38,
+ "start": 60,
+ "end": 93
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 62,
+ "endLine": 3,
+ "endColumn": 67,
+ "start": 117,
+ "end": 122
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "First Alternative Header",
+ "value": {
+ "type": "Literal",
+ "value": "First Alternative Header"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 38,
+ "endLine": 3,
+ "endColumn": 62,
+ "start": 93,
+ "end": 117
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/expected.js
new file mode 100644
index 0000000000..b2fd3f09eb
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/expected.js
@@ -0,0 +1,16 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`Visible Header
`;
+const $fragment2 = parseFragment`First Alternative Header
`;
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { st: api_static_fragment, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : $cmp.elseifCondition
+ ? api_fragment(0, [api_static_fragment($fragment2(), 4)], 0)
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/html-elements/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/actual.html
new file mode 100644
index 0000000000..bf66fe9cda
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/actual.html
@@ -0,0 +1,4 @@
+
+ Conditional Text
+ Elseif!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/ast.json
new file mode 100644
index 0000000000..9275928b9a
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/ast.json
@@ -0,0 +1,134 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 0,
+ "end": 138,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 127,
+ "end": 138
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 59,
+ "start": 15,
+ "end": 69
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 48,
+ "start": 42,
+ "end": 58
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 11,
+ "name": "displayAlt",
+ "location": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 38,
+ "start": 84,
+ "end": 107
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 57,
+ "start": 74,
+ "end": 126
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 38,
+ "start": 84,
+ "end": 107
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Elseif!",
+ "value": {
+ "type": "Literal",
+ "value": "Elseif!"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 39,
+ "endLine": 3,
+ "endColumn": 46,
+ "start": 108,
+ "end": 115
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/expected.js
new file mode 100644
index 0000000000..fd41f91074
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/expected.js
@@ -0,0 +1,14 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_text("Conditional Text")], 0)
+ : $cmp.displayAlt
+ ? api_fragment(0, [api_text("Elseif!")], 0)
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-elseif/template/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/actual.html
new file mode 100644
index 0000000000..68fd7d77c7
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/actual.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/ast.json
new file mode 100644
index 0000000000..bc0e35b440
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/ast.json
@@ -0,0 +1,101 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 3,
+ "endColumn": 12,
+ "start": 0,
+ "end": 65,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 1,
+ "endLine": 3,
+ "endColumn": 12,
+ "start": 54,
+ "end": 65
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 32,
+ "start": 15,
+ "end": 42
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 42,
+ "end": 53
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/expected.js
new file mode 100644
index 0000000000..6aeff73c86
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/expected.js
@@ -0,0 +1,16 @@
+import _cCustom from "c/custom";
+import { registerTemplate } from "lwc";
+const stc0 = {
+ key: 1,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { c: api_custom_element, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_custom_element("c-custom", _cCustom, stc0)], 0)
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/components/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/actual.html
new file mode 100644
index 0000000000..fcc808dff5
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/actual.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/ast.json
new file mode 100644
index 0000000000..82b372eec4
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/ast.json
@@ -0,0 +1,101 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 3,
+ "endColumn": 12,
+ "start": 0,
+ "end": 53,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 1,
+ "endLine": 3,
+ "endColumn": 12,
+ "start": 42,
+ "end": 53
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 15,
+ "end": 41
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 9,
+ "endLine": 2,
+ "endColumn": 25,
+ "start": 19,
+ "end": 35
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 15,
+ "end": 41,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 26,
+ "start": 15,
+ "end": 36
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 26,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 36,
+ "end": 41
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/expected.js
new file mode 100644
index 0000000000..c3f17917c1
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/expected.js
@@ -0,0 +1,13 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment``;
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { st: api_static_fragment, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/html-elements/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/actual.html
new file mode 100644
index 0000000000..3a0b07a4c4
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/actual.html
@@ -0,0 +1,3 @@
+
+ Conditional Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/ast.json
new file mode 100644
index 0000000000..3bac6918e3
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/ast.json
@@ -0,0 +1,83 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 3,
+ "endColumn": 12,
+ "start": 0,
+ "end": 81,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 1,
+ "endLine": 3,
+ "endColumn": 12,
+ "start": 70,
+ "end": 81
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 59,
+ "start": 15,
+ "end": 69
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 48,
+ "start": 42,
+ "end": 58
+ }
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/expected.js
new file mode 100644
index 0000000000..773006ae00
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/expected.js
@@ -0,0 +1,10 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, fr: api_fragment } = $api;
+ return [
+ $cmp.visible ? api_fragment(0, [api_text("Conditional Text")], 0) : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/if-only/template/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/actual.html
new file mode 100644
index 0000000000..07b85d7695
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/actual.html
@@ -0,0 +1,4 @@
+
+ Conditional Iteration
+ Else Iteration
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/ast.json
new file mode 100644
index 0000000000..ca9a0548b6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/ast.json
@@ -0,0 +1,214 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 0,
+ "end": 204,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 1,
+ "endLine": 4,
+ "endColumn": 12,
+ "start": 193,
+ "end": 204
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 48,
+ "endLine": 2,
+ "endColumn": 64,
+ "start": 58,
+ "end": 74
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 97,
+ "start": 15,
+ "end": 107
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 48,
+ "endLine": 2,
+ "endColumn": 64,
+ "start": 58,
+ "end": 74
+ },
+ "children": [
+ {
+ "type": "ForEach",
+ "expression": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 6,
+ "name": "items",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "item": {
+ "type": "Identifier",
+ "name": "item",
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 47,
+ "start": 42,
+ "end": 57
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 97,
+ "start": 15,
+ "end": 107
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Iteration",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Iteration"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 65,
+ "endLine": 2,
+ "endColumn": 86,
+ "start": 75,
+ "end": 96
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 85,
+ "start": 112,
+ "end": 192
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 51,
+ "endLine": 3,
+ "endColumn": 59,
+ "start": 158,
+ "end": 166
+ },
+ "children": [
+ {
+ "type": "ForEach",
+ "expression": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 9,
+ "name": "altItems",
+ "location": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 34,
+ "start": 122,
+ "end": 141
+ }
+ },
+ "item": {
+ "type": "Identifier",
+ "name": "item",
+ "location": {
+ "startLine": 3,
+ "startColumn": 35,
+ "endLine": 3,
+ "endColumn": 50,
+ "start": 142,
+ "end": 157
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 85,
+ "start": 112,
+ "end": 192
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 34,
+ "start": 122,
+ "end": 141
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else Iteration",
+ "value": {
+ "type": "Literal",
+ "value": "Else Iteration"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 60,
+ "endLine": 3,
+ "endColumn": 74,
+ "start": 167,
+ "end": 181
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/expected.js
new file mode 100644
index 0000000000..f85b6be89d
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/expected.js
@@ -0,0 +1,24 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, i: api_iterator, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(
+ 0,
+ api_iterator($cmp.items, function (item) {
+ return api_text("Conditional Iteration");
+ }),
+ 0
+ )
+ : api_fragment(
+ 0,
+ api_iterator($cmp.altItems, function (item) {
+ return api_text("Else Iteration");
+ }),
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/foreach-if/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/actual.html
new file mode 100644
index 0000000000..8b39f1cde0
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/actual.html
@@ -0,0 +1,4 @@
+
+ If!
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/metadata.json
new file mode 100644
index 0000000000..c8c8d583f7
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-else/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1165,
+ "message": "LWC1165: 'lwc:else' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 62,
+ "length": 35
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/actual.html
new file mode 100644
index 0000000000..c518b54fa4
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/actual.html
@@ -0,0 +1,4 @@
+
+ If!
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/metadata.json
new file mode 100644
index 0000000000..45a74f0676
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/if-true-elseif/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1165,
+ "message": "LWC1165: 'lwc:elseif' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 62,
+ "length": 55
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/actual.html
new file mode 100644
index 0000000000..3dc4fe4822
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/actual.html
@@ -0,0 +1,4 @@
+
+ Conditional Text
+ Conditional Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/metadata.json
new file mode 100644
index 0000000000..83e5dca5e3
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-else/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1166,
+ "message": "LWC1166: 'if:true' directive cannot be used with 'lwc:if', 'lwc:elseif', or 'lwc:else directives on the same element.",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 74,
+ "length": 64
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/actual.html
new file mode 100644
index 0000000000..a43bf156aa
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/actual.html
@@ -0,0 +1,4 @@
+
+ Conditional Text
+ Elseif Text
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/metadata.json
new file mode 100644
index 0000000000..126a259441
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/interop/mixed-if-true-elseif/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1166,
+ "message": "LWC1166: 'if:true' directive cannot be used with 'lwc:if', 'lwc:elseif', or 'lwc:else directives on the same element.",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 74,
+ "length": 70
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/actual.html
new file mode 100644
index 0000000000..29ecab7278
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/actual.html
@@ -0,0 +1,5 @@
+
+ Conditional Text
+ Elseif!
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/ast.json
new file mode 100644
index 0000000000..3c98e0bef7
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/ast.json
@@ -0,0 +1,241 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 0,
+ "end": 175,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 164,
+ "end": 175
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 59,
+ "start": 15,
+ "end": 69
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 48,
+ "start": 42,
+ "end": 58
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 16,
+ "name": "elseifCondition",
+ "location": {
+ "startLine": 3,
+ "startColumn": 10,
+ "endLine": 3,
+ "endColumn": 38,
+ "start": 79,
+ "end": 107
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 52,
+ "start": 74,
+ "end": 121
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 10,
+ "endLine": 3,
+ "endColumn": 38,
+ "start": 79,
+ "end": 107
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 52,
+ "start": 74,
+ "end": 121,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 39,
+ "start": 74,
+ "end": 108
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 46,
+ "endLine": 3,
+ "endColumn": 52,
+ "start": 115,
+ "end": 121
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Elseif!",
+ "value": {
+ "type": "Literal",
+ "value": "Elseif!"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 39,
+ "endLine": 3,
+ "endColumn": 46,
+ "start": 108,
+ "end": 115
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 42,
+ "start": 126,
+ "end": 163
+ },
+ "directiveLocation": {
+ "startLine": 4,
+ "startColumn": 16,
+ "endLine": 4,
+ "endColumn": 24,
+ "start": 137,
+ "end": 145
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-default",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 42,
+ "start": 126,
+ "end": 163,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 25,
+ "start": 126,
+ "end": 146
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 30,
+ "endLine": 4,
+ "endColumn": 42,
+ "start": 151,
+ "end": 163
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else!",
+ "value": {
+ "type": "Literal",
+ "value": "Else!"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 25,
+ "endLine": 4,
+ "endColumn": 30,
+ "start": 146,
+ "end": 151
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/expected.js
new file mode 100644
index 0000000000..7721e8bf75
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/expected.js
@@ -0,0 +1,32 @@
+import _cDefault from "c/default";
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`Elseif!
`;
+const stc0 = {
+ key: 3,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ t: api_text,
+ fr: api_fragment,
+ st: api_static_fragment,
+ c: api_custom_element,
+ } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_text("Conditional Text")], 0)
+ : $cmp.elseifCondition
+ ? api_fragment(0, [api_static_fragment($fragment1(), 2)], 0)
+ : api_fragment(
+ 0,
+ [
+ api_custom_element("c-default", _cDefault, stc0, [
+ api_text("Else!"),
+ ]),
+ ],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/mixed-elements/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/actual.html
new file mode 100644
index 0000000000..207746baa6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/actual.html
@@ -0,0 +1,13 @@
+
+
+
+ If Text
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/ast.json
new file mode 100644
index 0000000000..f281a8abb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/ast.json
@@ -0,0 +1,560 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 13,
+ "endColumn": 12,
+ "start": 0,
+ "end": 510,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 13,
+ "startColumn": 1,
+ "endLine": 13,
+ "endColumn": 12,
+ "start": 499,
+ "end": 510
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 15,
+ "end": 53,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 32,
+ "start": 15,
+ "end": 42
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 43,
+ "start": 42,
+ "end": 53
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 7,
+ "name": "elseif",
+ "location": {
+ "startLine": 3,
+ "startColumn": 22,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 75,
+ "end": 94
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 11,
+ "endColumn": 23,
+ "start": 58,
+ "end": 453
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 22,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 75,
+ "end": 94
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom-elseif",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 11,
+ "endColumn": 23,
+ "start": 58,
+ "end": 453,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 42,
+ "start": 58,
+ "end": 95
+ },
+ "endTag": {
+ "startLine": 11,
+ "startColumn": 5,
+ "endLine": 11,
+ "endColumn": 23,
+ "start": 435,
+ "end": 453
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "If Text",
+ "value": {
+ "type": "Literal",
+ "value": "If Text"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 42,
+ "endLine": 5,
+ "endColumn": 9,
+ "start": 95,
+ "end": 120
+ }
+ },
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 13,
+ "name": "showNestedIf",
+ "location": {
+ "startLine": 5,
+ "startColumn": 19,
+ "endLine": 5,
+ "endColumn": 40,
+ "start": 130,
+ "end": 151
+ }
+ },
+ "location": {
+ "startLine": 5,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 20,
+ "start": 120,
+ "end": 311
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 19,
+ "endLine": 5,
+ "endColumn": 40,
+ "start": 130,
+ "end": 151
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-nested",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 5,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 20,
+ "start": 120,
+ "end": 311,
+ "startTag": {
+ "startLine": 5,
+ "startColumn": 9,
+ "endLine": 5,
+ "endColumn": 41,
+ "start": 120,
+ "end": 152
+ },
+ "endTag": {
+ "startLine": 8,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 20,
+ "start": 300,
+ "end": 311
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 15,
+ "name": "doubleNestedIf",
+ "location": {
+ "startLine": 6,
+ "startColumn": 30,
+ "endLine": 6,
+ "endColumn": 53,
+ "start": 182,
+ "end": 205
+ }
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 72,
+ "start": 165,
+ "end": 224
+ },
+ "directiveLocation": {
+ "startLine": 6,
+ "startColumn": 30,
+ "endLine": 6,
+ "endColumn": 53,
+ "start": 182,
+ "end": 205
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-double-nested",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 72,
+ "start": 165,
+ "end": 224,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 54,
+ "start": 165,
+ "end": 206
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 54,
+ "endLine": 6,
+ "endColumn": 72,
+ "start": 206,
+ "end": 224
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 67,
+ "start": 237,
+ "end": 291
+ },
+ "directiveLocation": {
+ "startLine": 7,
+ "startColumn": 35,
+ "endLine": 7,
+ "endColumn": 43,
+ "start": 259,
+ "end": 267
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-double-nested-else",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 67,
+ "start": 237,
+ "end": 291,
+ "startTag": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 44,
+ "start": 237,
+ "end": 268
+ },
+ "endTag": {
+ "startLine": 7,
+ "startColumn": 44,
+ "endLine": 7,
+ "endColumn": 67,
+ "start": 268,
+ "end": 291
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 13,
+ "name": "elseifNested",
+ "location": {
+ "startLine": 9,
+ "startColumn": 26,
+ "endLine": 9,
+ "endColumn": 51,
+ "start": 337,
+ "end": 362
+ }
+ },
+ "location": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 70,
+ "start": 320,
+ "end": 381
+ },
+ "directiveLocation": {
+ "startLine": 9,
+ "startColumn": 26,
+ "endLine": 9,
+ "endColumn": 51,
+ "start": 337,
+ "end": 362
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-nested-elseif",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 70,
+ "start": 320,
+ "end": 381,
+ "startTag": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 52,
+ "start": 320,
+ "end": 363
+ },
+ "endTag": {
+ "startLine": 9,
+ "startColumn": 52,
+ "endLine": 9,
+ "endColumn": 70,
+ "start": 363,
+ "end": 381
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 10,
+ "startColumn": 9,
+ "endLine": 10,
+ "endColumn": 49,
+ "start": 390,
+ "end": 430
+ },
+ "directiveLocation": {
+ "startLine": 10,
+ "startColumn": 24,
+ "endLine": 10,
+ "endColumn": 32,
+ "start": 405,
+ "end": 413
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-nested-else",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 10,
+ "startColumn": 9,
+ "endLine": 10,
+ "endColumn": 49,
+ "start": 390,
+ "end": 430,
+ "startTag": {
+ "startLine": 10,
+ "startColumn": 9,
+ "endLine": 10,
+ "endColumn": 33,
+ "start": 390,
+ "end": 414
+ },
+ "endTag": {
+ "startLine": 10,
+ "startColumn": 33,
+ "endLine": 10,
+ "endColumn": 49,
+ "start": 414,
+ "end": 430
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 12,
+ "startColumn": 5,
+ "endLine": 12,
+ "endColumn": 45,
+ "start": 458,
+ "end": 498
+ },
+ "directiveLocation": {
+ "startLine": 12,
+ "startColumn": 20,
+ "endLine": 12,
+ "endColumn": 28,
+ "start": 473,
+ "end": 481
+ },
+ "children": [
+ {
+ "type": "Component",
+ "name": "c-custom-else",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 12,
+ "startColumn": 5,
+ "endLine": 12,
+ "endColumn": 45,
+ "start": 458,
+ "end": 498,
+ "startTag": {
+ "startLine": 12,
+ "startColumn": 5,
+ "endLine": 12,
+ "endColumn": 29,
+ "start": 458,
+ "end": 482
+ },
+ "endTag": {
+ "startLine": 12,
+ "startColumn": 29,
+ "endLine": 12,
+ "endColumn": 45,
+ "start": 482,
+ "end": 498
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/expected.js
new file mode 100644
index 0000000000..5ef9c96356
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/expected.js
@@ -0,0 +1,107 @@
+import _cCustom from "c/custom";
+import _cDoubleNested from "c/doubleNested";
+import _cDoubleNestedElse from "c/doubleNestedElse";
+import _cNested from "c/nested";
+import _cNestedElseif from "c/nestedElseif";
+import _cNestedElse from "c/nestedElse";
+import _cCustomElseif from "c/customElseif";
+import _cCustomElse from "c/customElse";
+import { registerTemplate } from "lwc";
+const stc0 = {
+ key: 1,
+};
+const stc1 = {
+ key: 2,
+};
+const stc2 = {
+ key: 4,
+};
+const stc3 = {
+ key: 6,
+};
+const stc4 = {
+ key: 7,
+};
+const stc5 = {
+ key: 8,
+};
+const stc6 = {
+ key: 9,
+};
+const stc7 = {
+ key: 10,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { c: api_custom_element, fr: api_fragment, t: api_text } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_custom_element("c-custom", _cCustom, stc0)], 0)
+ : $cmp.elseif
+ ? api_fragment(
+ 0,
+ [
+ api_custom_element("c-custom-elseif", _cCustomElseif, stc1, [
+ api_text("If Text"),
+ $cmp.showNestedIf
+ ? api_fragment(
+ 3,
+ [
+ api_custom_element("c-nested", _cNested, stc2, [
+ $cmp.doubleNestedIf
+ ? api_fragment(
+ 5,
+ [
+ api_custom_element(
+ "c-double-nested",
+ _cDoubleNested,
+ stc3
+ ),
+ ],
+ 0
+ )
+ : api_fragment(
+ 5,
+ [
+ api_custom_element(
+ "c-double-nested-else",
+ _cDoubleNestedElse,
+ stc4
+ ),
+ ],
+ 0
+ ),
+ ]),
+ ],
+ 0
+ )
+ : $cmp.elseifNested
+ ? api_fragment(
+ 3,
+ [
+ api_custom_element(
+ "c-nested-elseif",
+ _cNestedElseif,
+ stc5
+ ),
+ ],
+ 0
+ )
+ : api_fragment(
+ 3,
+ [api_custom_element("c-nested-else", _cNestedElse, stc6)],
+ 0
+ ),
+ ]),
+ ],
+ 0
+ )
+ : api_fragment(
+ 0,
+ [api_custom_element("c-custom-else", _cCustomElse, stc7)],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/nested/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/actual.html
new file mode 100644
index 0000000000..36ed011564
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/actual.html
@@ -0,0 +1,5 @@
+
+ Conditional Text
+
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/ast.json
new file mode 100644
index 0000000000..ad8f740076
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/ast.json
@@ -0,0 +1,133 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 0,
+ "end": 142,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 1,
+ "endLine": 5,
+ "endColumn": 12,
+ "start": 131,
+ "end": 142
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 59,
+ "start": 15,
+ "end": 69
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 2,
+ "endColumn": 48,
+ "start": 42,
+ "end": 58
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 4,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 40,
+ "start": 95,
+ "end": 130
+ },
+ "directiveLocation": {
+ "startLine": 4,
+ "startColumn": 15,
+ "endLine": 4,
+ "endColumn": 23,
+ "start": 105,
+ "end": 113
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else!",
+ "value": {
+ "type": "Literal",
+ "value": "Else!"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 24,
+ "endLine": 4,
+ "endColumn": 29,
+ "start": 114,
+ "end": 119
+ }
+ }
+ ]
+ }
+ },
+ {
+ "type": "Comment",
+ "raw": " Comment ",
+ "value": " Comment ",
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 3,
+ "endColumn": 21,
+ "start": 74,
+ "end": 90
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/expected.js
new file mode 100644
index 0000000000..2be1cdb2ee
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/expected.js
@@ -0,0 +1,12 @@
+import { registerTemplate } from "lwc";
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(0, [api_text("Conditional Text")], 0)
+ : api_fragment(0, [api_text("Else!")], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-disabled/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/actual.html
new file mode 100644
index 0000000000..36ed011564
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/actual.html
@@ -0,0 +1,5 @@
+
+ Conditional Text
+
+ Else!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/config.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/config.json
new file mode 100644
index 0000000000..64e77756cd
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/config.json
@@ -0,0 +1,3 @@
+{
+ "preserveHtmlComments": true
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/metadata.json
new file mode 100644
index 0000000000..6a5b35a636
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/preserve-comments/preserve-comments-enabled/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1165,
+ "message": "LWC1165: 'lwc:else' directive must be used immediately after an element with 'lwc:if' or 'lwc:elseif'. No such element found.",
+ "level": 1,
+ "location": {
+ "line": 4,
+ "column": 5,
+ "start": 95,
+ "length": 35
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/actual.html
new file mode 100644
index 0000000000..317c5cd7cd
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/actual.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/ast.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/ast.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/expected.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/metadata.json
new file mode 100644
index 0000000000..0da08c0eb6
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/no-directives-in-slots/metadata.json
@@ -0,0 +1,26 @@
+{
+ "warnings": [
+ {
+ "code": 1082,
+ "message": "LWC1082: Slot tag can't be associated with directives",
+ "level": 1,
+ "location": {
+ "line": 2,
+ "column": 5,
+ "start": 15,
+ "length": 56
+ }
+ },
+ {
+ "code": 1082,
+ "message": "LWC1082: Slot tag can't be associated with directives",
+ "level": 1,
+ "location": {
+ "line": 3,
+ "column": 5,
+ "start": 76,
+ "length": 46
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/actual.html
new file mode 100644
index 0000000000..5264fa74bb
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/actual.html
@@ -0,0 +1,21 @@
+
+
+ Conditional Text
+
+
+
+
+
+
+
+
+
+
+ Another Conditional Text
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/ast.json
new file mode 100644
index 0000000000..a9e1076860
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/ast.json
@@ -0,0 +1,451 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 21,
+ "endColumn": 12,
+ "start": 0,
+ "end": 540,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 21,
+ "startColumn": 1,
+ "endLine": 21,
+ "endColumn": 12,
+ "start": 529,
+ "end": 540
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 10,
+ "name": "condition",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 33,
+ "start": 25,
+ "end": 43
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 85
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 33,
+ "start": 25,
+ "end": 43
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 34,
+ "endLine": 4,
+ "endColumn": 5,
+ "start": 44,
+ "end": 74
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 13,
+ "name": "altCondition",
+ "location": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 40,
+ "start": 100,
+ "end": 125
+ }
+ },
+ "location": {
+ "startLine": 5,
+ "startColumn": 5,
+ "endLine": 9,
+ "endColumn": 16,
+ "start": 90,
+ "end": 217
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 40,
+ "start": 100,
+ "end": 125
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 15,
+ "start": 135,
+ "end": 201,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 14,
+ "start": 135,
+ "end": 140
+ },
+ "endTag": {
+ "startLine": 8,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 15,
+ "start": 195,
+ "end": 201
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "outside-slot",
+ "location": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 46,
+ "start": 153,
+ "end": 186,
+ "startTag": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 39,
+ "start": 153,
+ "end": 179
+ },
+ "endTag": {
+ "startLine": 7,
+ "startColumn": 39,
+ "endLine": 7,
+ "endColumn": 46,
+ "start": 179,
+ "end": 186
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "outside-slot"
+ },
+ "location": {
+ "startLine": 7,
+ "startColumn": 19,
+ "endLine": 7,
+ "endColumn": 38,
+ "start": 159,
+ "end": 178
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 10,
+ "startColumn": 5,
+ "endLine": 12,
+ "endColumn": 16,
+ "start": 222,
+ "end": 299
+ },
+ "directiveLocation": {
+ "startLine": 10,
+ "startColumn": 15,
+ "endLine": 10,
+ "endColumn": 23,
+ "start": 232,
+ "end": 240
+ },
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "outside-slot",
+ "location": {
+ "startLine": 11,
+ "startColumn": 9,
+ "endLine": 11,
+ "endColumn": 42,
+ "start": 250,
+ "end": 283,
+ "startTag": {
+ "startLine": 11,
+ "startColumn": 9,
+ "endLine": 11,
+ "endColumn": 35,
+ "start": 250,
+ "end": 276
+ },
+ "endTag": {
+ "startLine": 11,
+ "startColumn": 35,
+ "endLine": 11,
+ "endColumn": 42,
+ "start": 276,
+ "end": 283
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "outside-slot"
+ },
+ "location": {
+ "startLine": 11,
+ "startColumn": 15,
+ "endLine": 11,
+ "endColumn": 34,
+ "start": 256,
+ "end": 275
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ },
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 17,
+ "name": "anotherCondition",
+ "location": {
+ "startLine": 13,
+ "startColumn": 15,
+ "endLine": 13,
+ "endColumn": 40,
+ "start": 314,
+ "end": 339
+ }
+ },
+ "location": {
+ "startLine": 13,
+ "startColumn": 5,
+ "endLine": 15,
+ "endColumn": 16,
+ "start": 304,
+ "end": 389
+ },
+ "directiveLocation": {
+ "startLine": 13,
+ "startColumn": 15,
+ "endLine": 13,
+ "endColumn": 40,
+ "start": 314,
+ "end": 339
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Another Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Another Conditional Text"
+ },
+ "location": {
+ "startLine": 13,
+ "startColumn": 41,
+ "endLine": 15,
+ "endColumn": 5,
+ "start": 340,
+ "end": 378
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 20,
+ "name": "anotherAltCondition",
+ "location": {
+ "startLine": 16,
+ "startColumn": 15,
+ "endLine": 16,
+ "endColumn": 47,
+ "start": 404,
+ "end": 436
+ }
+ },
+ "location": {
+ "startLine": 16,
+ "startColumn": 5,
+ "endLine": 20,
+ "endColumn": 16,
+ "start": 394,
+ "end": 528
+ },
+ "directiveLocation": {
+ "startLine": 16,
+ "startColumn": 15,
+ "endLine": 16,
+ "endColumn": 47,
+ "start": 404,
+ "end": 436
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 17,
+ "startColumn": 9,
+ "endLine": 19,
+ "endColumn": 15,
+ "start": 446,
+ "end": 512,
+ "startTag": {
+ "startLine": 17,
+ "startColumn": 9,
+ "endLine": 17,
+ "endColumn": 14,
+ "start": 446,
+ "end": 451
+ },
+ "endTag": {
+ "startLine": 19,
+ "startColumn": 9,
+ "endLine": 19,
+ "endColumn": 15,
+ "start": 506,
+ "end": 512
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "outside-slot",
+ "location": {
+ "startLine": 18,
+ "startColumn": 13,
+ "endLine": 18,
+ "endColumn": 46,
+ "start": 464,
+ "end": 497,
+ "startTag": {
+ "startLine": 18,
+ "startColumn": 13,
+ "endLine": 18,
+ "endColumn": 39,
+ "start": 464,
+ "end": 490
+ },
+ "endTag": {
+ "startLine": 18,
+ "startColumn": 39,
+ "endLine": 18,
+ "endColumn": 46,
+ "start": 490,
+ "end": 497
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "outside-slot"
+ },
+ "location": {
+ "startLine": 18,
+ "startColumn": 19,
+ "endLine": 18,
+ "endColumn": 38,
+ "start": 470,
+ "end": 489
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/expected.js
new file mode 100644
index 0000000000..8d5abdb865
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/expected.js
@@ -0,0 +1,61 @@
+import { registerTemplate } from "lwc";
+const stc0 = {
+ key: 1,
+};
+const stc1 = {
+ attrs: {
+ name: "outside-slot",
+ },
+ key: 2,
+};
+const stc2 = [];
+const stc3 = {
+ attrs: {
+ name: "outside-slot",
+ },
+ key: 3,
+};
+const stc4 = {
+ key: 5,
+};
+const stc5 = {
+ attrs: {
+ name: "outside-slot",
+ },
+ key: 6,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, fr: api_fragment, s: api_slot, h: api_element } = $api;
+ return [
+ $cmp.condition
+ ? api_fragment(0, [api_text("Conditional Text")], 0)
+ : $cmp.altCondition
+ ? api_fragment(
+ 0,
+ [
+ api_element("div", stc0, [
+ api_slot("outside-slot", stc1, stc2, $slotset),
+ ]),
+ ],
+ 0
+ )
+ : api_fragment(0, [api_slot("outside-slot", stc3, stc2, $slotset)], 0),
+ $cmp.anotherCondition
+ ? api_fragment(4, [api_text("Another Conditional Text")], 0)
+ : $cmp.anotherAltCondition
+ ? api_fragment(
+ 4,
+ [
+ api_element("div", stc4, [
+ api_slot("outside-slot", stc5, stc2, $slotset),
+ ]),
+ ],
+ 0
+ )
+ : null,
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.slots = ["outside-slot"];
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/metadata.json
new file mode 100644
index 0000000000..cdf228d12c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/not-in-same-condition-tree/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1137,
+ "message": "LWC1137: Invalid duplicate slot (name=\"outside-slot\").",
+ "level": 2,
+ "location": {
+ "line": 18,
+ "column": 13,
+ "start": 464,
+ "length": 33
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/actual.html
new file mode 100644
index 0000000000..17e5c9edc0
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/actual.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+ Alternative Text
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/ast.json
new file mode 100644
index 0000000000..80fb0084c3
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/ast.json
@@ -0,0 +1,243 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 11,
+ "endColumn": 12,
+ "start": 0,
+ "end": 252,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 11,
+ "startColumn": 1,
+ "endLine": 11,
+ "endColumn": 12,
+ "start": 241,
+ "end": 252
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 10,
+ "name": "condition",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 33,
+ "start": 25,
+ "end": 43
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 16,
+ "start": 15,
+ "end": 175
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 33,
+ "start": 25,
+ "end": 43
+ },
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "nested-slot",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 53,
+ "end": 85,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 34,
+ "start": 53,
+ "end": 78
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 34,
+ "endLine": 3,
+ "endColumn": 41,
+ "start": 78,
+ "end": 85
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "nested-slot"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 33,
+ "start": 59,
+ "end": 77
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ },
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 15,
+ "start": 94,
+ "end": 159,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 4,
+ "endColumn": 14,
+ "start": 94,
+ "end": 99
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 15,
+ "start": 153,
+ "end": 159
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "nested-slot",
+ "location": {
+ "startLine": 5,
+ "startColumn": 13,
+ "endLine": 5,
+ "endColumn": 45,
+ "start": 112,
+ "end": 144,
+ "startTag": {
+ "startLine": 5,
+ "startColumn": 13,
+ "endLine": 5,
+ "endColumn": 38,
+ "start": 112,
+ "end": 137
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 38,
+ "endLine": 5,
+ "endColumn": 45,
+ "start": 137,
+ "end": 144
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "nested-slot"
+ },
+ "location": {
+ "startLine": 5,
+ "startColumn": 19,
+ "endLine": 5,
+ "endColumn": 37,
+ "start": 118,
+ "end": 136
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 8,
+ "startColumn": 5,
+ "endLine": 10,
+ "endColumn": 16,
+ "start": 180,
+ "end": 240
+ },
+ "directiveLocation": {
+ "startLine": 8,
+ "startColumn": 15,
+ "endLine": 8,
+ "endColumn": 23,
+ "start": 190,
+ "end": 198
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Alternative Text",
+ "value": {
+ "type": "Literal",
+ "value": "Alternative Text"
+ },
+ "location": {
+ "startLine": 8,
+ "startColumn": 24,
+ "endLine": 10,
+ "endColumn": 5,
+ "start": 199,
+ "end": 229
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/expected.js
new file mode 100644
index 0000000000..7e305d7fb8
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/expected.js
@@ -0,0 +1,38 @@
+import { registerTemplate } from "lwc";
+const stc0 = {
+ attrs: {
+ name: "nested-slot",
+ },
+ key: 1,
+};
+const stc1 = [];
+const stc2 = {
+ key: 2,
+};
+const stc3 = {
+ attrs: {
+ name: "nested-slot",
+ },
+ key: 3,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { s: api_slot, h: api_element, fr: api_fragment, t: api_text } = $api;
+ return [
+ $cmp.condition
+ ? api_fragment(
+ 0,
+ [
+ api_slot("nested-slot", stc0, stc1, $slotset),
+ api_element("div", stc2, [
+ api_slot("nested-slot", stc3, stc1, $slotset),
+ ]),
+ ],
+ 0
+ )
+ : api_fragment(0, [api_text("Alternative Text")], 0),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.slots = ["nested-slot"];
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/metadata.json
new file mode 100644
index 0000000000..a40aae4f44
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/same-branch-condition-tree/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1137,
+ "message": "LWC1137: Invalid duplicate slot (name=\"nested-slot\").",
+ "level": 2,
+ "location": {
+ "line": 5,
+ "column": 13,
+ "start": 112,
+ "length": 32
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/actual.html
new file mode 100644
index 0000000000..6c424a31e1
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/actual.html
@@ -0,0 +1,11 @@
+
+
+ Separator
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/ast.json
new file mode 100644
index 0000000000..1bca535439
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/ast.json
@@ -0,0 +1,292 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 11,
+ "endColumn": 12,
+ "start": 0,
+ "end": 214,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 11,
+ "startColumn": 1,
+ "endLine": 11,
+ "endColumn": 12,
+ "start": 203,
+ "end": 214
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 6,
+ "endColumn": 11,
+ "start": 15,
+ "end": 110,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 10,
+ "start": 15,
+ "end": 20
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 5,
+ "endLine": 6,
+ "endColumn": 11,
+ "start": 104,
+ "end": 110
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 5,
+ "endColumn": 15,
+ "start": 29,
+ "end": 99,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 14,
+ "start": 29,
+ "end": 34
+ },
+ "endTag": {
+ "startLine": 5,
+ "startColumn": 9,
+ "endLine": 5,
+ "endColumn": 15,
+ "start": 93,
+ "end": 99
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "conditional-slot",
+ "location": {
+ "startLine": 4,
+ "startColumn": 13,
+ "endLine": 4,
+ "endColumn": 50,
+ "start": 47,
+ "end": 84,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 13,
+ "endLine": 4,
+ "endColumn": 43,
+ "start": 47,
+ "end": 77
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 43,
+ "endLine": 4,
+ "endColumn": 50,
+ "start": 77,
+ "end": 84
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "conditional-slot"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 19,
+ "endLine": 4,
+ "endColumn": 42,
+ "start": 53,
+ "end": 76
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 7,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 25,
+ "start": 115,
+ "end": 135,
+ "startTag": {
+ "startLine": 7,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 10,
+ "start": 115,
+ "end": 120
+ },
+ "endTag": {
+ "startLine": 7,
+ "startColumn": 19,
+ "endLine": 7,
+ "endColumn": 25,
+ "start": 129,
+ "end": 135
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Separator",
+ "value": {
+ "type": "Literal",
+ "value": "Separator"
+ },
+ "location": {
+ "startLine": 7,
+ "startColumn": 10,
+ "endLine": 7,
+ "endColumn": 19,
+ "start": 120,
+ "end": 129
+ }
+ }
+ ]
+ },
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 8,
+ "startColumn": 5,
+ "endLine": 10,
+ "endColumn": 11,
+ "start": 140,
+ "end": 202,
+ "startTag": {
+ "startLine": 8,
+ "startColumn": 5,
+ "endLine": 8,
+ "endColumn": 10,
+ "start": 140,
+ "end": 145
+ },
+ "endTag": {
+ "startLine": 10,
+ "startColumn": 5,
+ "endLine": 10,
+ "endColumn": 11,
+ "start": 196,
+ "end": 202
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "conditional-slot",
+ "location": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 46,
+ "start": 154,
+ "end": 191,
+ "startTag": {
+ "startLine": 9,
+ "startColumn": 9,
+ "endLine": 9,
+ "endColumn": 39,
+ "start": 154,
+ "end": 184
+ },
+ "endTag": {
+ "startLine": 9,
+ "startColumn": 39,
+ "endLine": 9,
+ "endColumn": 46,
+ "start": 184,
+ "end": 191
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "conditional-slot"
+ },
+ "location": {
+ "startLine": 9,
+ "startColumn": 15,
+ "endLine": 9,
+ "endColumn": 38,
+ "start": 160,
+ "end": 183
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/expected.js
new file mode 100644
index 0000000000..12beb4b514
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/expected.js
@@ -0,0 +1,42 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`Separator
`;
+const stc0 = {
+ key: 0,
+};
+const stc1 = {
+ key: 1,
+};
+const stc2 = {
+ attrs: {
+ name: "conditional-slot",
+ },
+ key: 2,
+};
+const stc3 = [];
+const stc4 = {
+ key: 5,
+};
+const stc5 = {
+ attrs: {
+ name: "conditional-slot",
+ },
+ key: 6,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { s: api_slot, h: api_element, st: api_static_fragment } = $api;
+ return [
+ api_element("div", stc0, [
+ api_element("div", stc1, [
+ api_slot("conditional-slot", stc2, stc3, $slotset),
+ ]),
+ ]),
+ api_static_fragment($fragment1(), 4),
+ api_element("div", stc4, [
+ api_slot("conditional-slot", stc5, stc3, $slotset),
+ ]),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.slots = ["conditional-slot"];
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/metadata.json
new file mode 100644
index 0000000000..03aeef9f81
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/duplicate-slots-warning/simple/metadata.json
@@ -0,0 +1,15 @@
+{
+ "warnings": [
+ {
+ "code": 1137,
+ "message": "LWC1137: Invalid duplicate slot (name=\"conditional-slot\").",
+ "level": 2,
+ "location": {
+ "line": 9,
+ "column": 9,
+ "start": 154,
+ "length": 37
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/actual.html
new file mode 100644
index 0000000000..8dbd7df7c2
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/actual.html
@@ -0,0 +1,31 @@
+
+
+
+
+ Conditional Nested Text
+
+
+
+
+ Double Nested
+
+
+
+
+ Triple Nested Text
+
+
+
+
+
+ Else
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/ast.json
new file mode 100644
index 0000000000..181be756e2
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/ast.json
@@ -0,0 +1,768 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 31,
+ "endColumn": 12,
+ "start": 0,
+ "end": 986,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 31,
+ "startColumn": 1,
+ "endLine": 31,
+ "endColumn": 12,
+ "start": 975,
+ "end": 986
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "outer-slot",
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 36,
+ "start": 15,
+ "end": 46,
+ "startTag": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 2,
+ "endColumn": 29,
+ "start": 15,
+ "end": 39
+ },
+ "endTag": {
+ "startLine": 2,
+ "startColumn": 29,
+ "endLine": 2,
+ "endColumn": 36,
+ "start": 39,
+ "end": 46
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "outer-slot"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 11,
+ "endLine": 2,
+ "endColumn": 28,
+ "start": 21,
+ "end": 38
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ },
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 10,
+ "name": "condition",
+ "location": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 33,
+ "start": 61,
+ "end": 79
+ }
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 5,
+ "endLine": 26,
+ "endColumn": 16,
+ "start": 51,
+ "end": 847
+ },
+ "directiveLocation": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 33,
+ "start": 61,
+ "end": 79
+ },
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 7,
+ "name": "nested",
+ "location": {
+ "startLine": 4,
+ "startColumn": 19,
+ "endLine": 4,
+ "endColumn": 34,
+ "start": 99,
+ "end": 114
+ }
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 7,
+ "endColumn": 20,
+ "start": 89,
+ "end": 216
+ },
+ "directiveLocation": {
+ "startLine": 4,
+ "startColumn": 19,
+ "endLine": 4,
+ "endColumn": 34,
+ "start": 99,
+ "end": 114
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Nested Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Nested Text"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 35,
+ "endLine": 6,
+ "endColumn": 13,
+ "start": 115,
+ "end": 164
+ }
+ },
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "nested-slot",
+ "location": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 45,
+ "start": 164,
+ "end": 196,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 13,
+ "endLine": 6,
+ "endColumn": 38,
+ "start": 164,
+ "end": 189
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 38,
+ "endLine": 6,
+ "endColumn": 45,
+ "start": 189,
+ "end": 196
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "nested-slot"
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 19,
+ "endLine": 6,
+ "endColumn": 37,
+ "start": 170,
+ "end": 188
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 8,
+ "startColumn": 9,
+ "endLine": 24,
+ "endColumn": 20,
+ "start": 225,
+ "end": 785
+ },
+ "directiveLocation": {
+ "startLine": 8,
+ "startColumn": 19,
+ "endLine": 8,
+ "endColumn": 27,
+ "start": 235,
+ "end": 243
+ },
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 13,
+ "name": "doubleNested",
+ "location": {
+ "startLine": 9,
+ "startColumn": 23,
+ "endLine": 9,
+ "endColumn": 44,
+ "start": 267,
+ "end": 288
+ }
+ },
+ "location": {
+ "startLine": 9,
+ "startColumn": 13,
+ "endLine": 11,
+ "endColumn": 24,
+ "start": 257,
+ "end": 343
+ },
+ "directiveLocation": {
+ "startLine": 9,
+ "startColumn": 23,
+ "endLine": 9,
+ "endColumn": 44,
+ "start": 267,
+ "end": 288
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Double Nested",
+ "value": {
+ "type": "Literal",
+ "value": "Double Nested"
+ },
+ "location": {
+ "startLine": 9,
+ "startColumn": 45,
+ "endLine": 11,
+ "endColumn": 13,
+ "start": 289,
+ "end": 332
+ }
+ }
+ ],
+ "else": {
+ "type": "ElseifBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 16,
+ "name": "doubleNestedAlt",
+ "location": {
+ "startLine": 12,
+ "startColumn": 23,
+ "endLine": 12,
+ "endColumn": 51,
+ "start": 366,
+ "end": 394
+ }
+ },
+ "location": {
+ "startLine": 12,
+ "startColumn": 13,
+ "endLine": 19,
+ "endColumn": 24,
+ "start": 356,
+ "end": 639
+ },
+ "directiveLocation": {
+ "startLine": 12,
+ "startColumn": 23,
+ "endLine": 12,
+ "endColumn": 51,
+ "start": 366,
+ "end": 394
+ },
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 13,
+ "name": "tripleNested",
+ "location": {
+ "startLine": 13,
+ "startColumn": 22,
+ "endLine": 13,
+ "endColumn": 43,
+ "start": 417,
+ "end": 438
+ }
+ },
+ "location": {
+ "startLine": 13,
+ "startColumn": 17,
+ "endLine": 18,
+ "endColumn": 23,
+ "start": 412,
+ "end": 615
+ },
+ "directiveLocation": {
+ "startLine": 13,
+ "startColumn": 22,
+ "endLine": 13,
+ "endColumn": 43,
+ "start": 417,
+ "end": 438
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 13,
+ "startColumn": 17,
+ "endLine": 18,
+ "endColumn": 23,
+ "start": 412,
+ "end": 615,
+ "startTag": {
+ "startLine": 13,
+ "startColumn": 17,
+ "endLine": 13,
+ "endColumn": 44,
+ "start": 412,
+ "end": 439
+ },
+ "endTag": {
+ "startLine": 18,
+ "startColumn": 17,
+ "endLine": 18,
+ "endColumn": 23,
+ "start": 609,
+ "end": 615
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Element",
+ "name": "div",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 14,
+ "startColumn": 21,
+ "endLine": 17,
+ "endColumn": 27,
+ "start": 460,
+ "end": 592,
+ "startTag": {
+ "startLine": 14,
+ "startColumn": 21,
+ "endLine": 14,
+ "endColumn": 26,
+ "start": 460,
+ "end": 465
+ },
+ "endTag": {
+ "startLine": 17,
+ "startColumn": 21,
+ "endLine": 17,
+ "endColumn": 27,
+ "start": 586,
+ "end": 592
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Triple Nested Text",
+ "value": {
+ "type": "Literal",
+ "value": "Triple Nested Text"
+ },
+ "location": {
+ "startLine": 14,
+ "startColumn": 26,
+ "endLine": 16,
+ "endColumn": 25,
+ "start": 465,
+ "end": 533
+ }
+ },
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "nested-slot",
+ "location": {
+ "startLine": 16,
+ "startColumn": 25,
+ "endLine": 16,
+ "endColumn": 57,
+ "start": 533,
+ "end": 565,
+ "startTag": {
+ "startLine": 16,
+ "startColumn": 25,
+ "endLine": 16,
+ "endColumn": 50,
+ "start": 533,
+ "end": 558
+ },
+ "endTag": {
+ "startLine": 16,
+ "startColumn": 50,
+ "endLine": 16,
+ "endColumn": 57,
+ "start": 558,
+ "end": 565
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "nested-slot"
+ },
+ "location": {
+ "startLine": 16,
+ "startColumn": 31,
+ "endLine": 16,
+ "endColumn": 49,
+ "start": 539,
+ "end": 557
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 20,
+ "startColumn": 13,
+ "endLine": 23,
+ "endColumn": 24,
+ "start": 652,
+ "end": 765
+ },
+ "directiveLocation": {
+ "startLine": 20,
+ "startColumn": 23,
+ "endLine": 20,
+ "endColumn": 31,
+ "start": 662,
+ "end": 670
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Else",
+ "value": {
+ "type": "Literal",
+ "value": "Else"
+ },
+ "location": {
+ "startLine": 20,
+ "startColumn": 32,
+ "endLine": 22,
+ "endColumn": 17,
+ "start": 671,
+ "end": 709
+ }
+ },
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "nested-slot",
+ "location": {
+ "startLine": 22,
+ "startColumn": 17,
+ "endLine": 22,
+ "endColumn": 49,
+ "start": 709,
+ "end": 741,
+ "startTag": {
+ "startLine": 22,
+ "startColumn": 17,
+ "endLine": 22,
+ "endColumn": 42,
+ "start": 709,
+ "end": 734
+ },
+ "endTag": {
+ "startLine": 22,
+ "startColumn": 42,
+ "endLine": 22,
+ "endColumn": 49,
+ "start": 734,
+ "end": 741
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "nested-slot"
+ },
+ "location": {
+ "startLine": 22,
+ "startColumn": 23,
+ "endLine": 22,
+ "endColumn": 41,
+ "start": 715,
+ "end": 733
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "conditional-slot",
+ "location": {
+ "startLine": 25,
+ "startColumn": 9,
+ "endLine": 25,
+ "endColumn": 46,
+ "start": 794,
+ "end": 831,
+ "startTag": {
+ "startLine": 25,
+ "startColumn": 9,
+ "endLine": 25,
+ "endColumn": 39,
+ "start": 794,
+ "end": 824
+ },
+ "endTag": {
+ "startLine": 25,
+ "startColumn": 39,
+ "endLine": 25,
+ "endColumn": 46,
+ "start": 824,
+ "end": 831
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "conditional-slot"
+ },
+ "location": {
+ "startLine": 25,
+ "startColumn": 15,
+ "endLine": 25,
+ "endColumn": 38,
+ "start": 800,
+ "end": 823
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 27,
+ "startColumn": 5,
+ "endLine": 30,
+ "endColumn": 16,
+ "start": 852,
+ "end": 974
+ },
+ "directiveLocation": {
+ "startLine": 27,
+ "startColumn": 15,
+ "endLine": 27,
+ "endColumn": 23,
+ "start": 862,
+ "end": 870
+ },
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "conditional-slot",
+ "location": {
+ "startLine": 28,
+ "startColumn": 9,
+ "endLine": 28,
+ "endColumn": 46,
+ "start": 880,
+ "end": 917,
+ "startTag": {
+ "startLine": 28,
+ "startColumn": 9,
+ "endLine": 28,
+ "endColumn": 39,
+ "start": 880,
+ "end": 910
+ },
+ "endTag": {
+ "startLine": 28,
+ "startColumn": 39,
+ "endLine": 28,
+ "endColumn": 46,
+ "start": 910,
+ "end": 917
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "conditional-slot"
+ },
+ "location": {
+ "startLine": 28,
+ "startColumn": 15,
+ "endLine": 28,
+ "endColumn": 38,
+ "start": 886,
+ "end": 909
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ },
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "nested-slot",
+ "location": {
+ "startLine": 29,
+ "startColumn": 9,
+ "endLine": 29,
+ "endColumn": 41,
+ "start": 926,
+ "end": 958,
+ "startTag": {
+ "startLine": 29,
+ "startColumn": 9,
+ "endLine": 29,
+ "endColumn": 34,
+ "start": 926,
+ "end": 951
+ },
+ "endTag": {
+ "startLine": 29,
+ "startColumn": 34,
+ "endLine": 29,
+ "endColumn": 41,
+ "start": 951,
+ "end": 958
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "nested-slot"
+ },
+ "location": {
+ "startLine": 29,
+ "startColumn": 15,
+ "endLine": 29,
+ "endColumn": 33,
+ "start": 932,
+ "end": 950
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/expected.js
new file mode 100644
index 0000000000..7a44fc5411
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/expected.js
@@ -0,0 +1,127 @@
+import { registerTemplate } from "lwc";
+const stc0 = {
+ attrs: {
+ name: "outer-slot",
+ },
+ key: 0,
+};
+const stc1 = [];
+const stc2 = {
+ attrs: {
+ name: "nested-slot",
+ },
+ key: 3,
+};
+const stc3 = {
+ key: 6,
+};
+const stc4 = {
+ key: 7,
+};
+const stc5 = {
+ attrs: {
+ name: "nested-slot",
+ },
+ key: 8,
+};
+const stc6 = {
+ attrs: {
+ name: "nested-slot",
+ },
+ key: 9,
+};
+const stc7 = {
+ attrs: {
+ name: "conditional-slot",
+ },
+ key: 10,
+};
+const stc8 = {
+ attrs: {
+ name: "conditional-slot",
+ },
+ key: 11,
+};
+const stc9 = {
+ attrs: {
+ name: "nested-slot",
+ },
+ key: 12,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { s: api_slot, t: api_text, fr: api_fragment, h: api_element } = $api;
+ return [
+ api_slot("outer-slot", stc0, stc1, $slotset),
+ $cmp.condition
+ ? api_fragment(
+ 1,
+ [
+ $cmp.nested
+ ? api_fragment(
+ 2,
+ [
+ api_text("Conditional Nested Text"),
+ api_slot("nested-slot", stc2, stc1, $slotset),
+ ],
+ 0
+ )
+ : api_fragment(
+ 2,
+ [
+ $cmp.doubleNested
+ ? api_fragment(4, [api_text("Double Nested")], 0)
+ : $cmp.doubleNestedAlt
+ ? api_fragment(
+ 4,
+ [
+ $cmp.tripleNested
+ ? api_fragment(
+ 5,
+ [
+ api_element("div", stc3, [
+ api_element("div", stc4, [
+ api_text("Triple Nested Text"),
+ api_slot(
+ "nested-slot",
+ stc5,
+ stc1,
+ $slotset
+ ),
+ ]),
+ ]),
+ ],
+ 0
+ )
+ : null,
+ ],
+ 0
+ )
+ : api_fragment(
+ 4,
+ [
+ api_text("Else"),
+ api_slot("nested-slot", stc6, stc1, $slotset),
+ ],
+ 0
+ ),
+ ],
+ 0
+ ),
+ api_slot("conditional-slot", stc7, stc1, $slotset),
+ ],
+ 0
+ )
+ : api_fragment(
+ 1,
+ [
+ api_slot("conditional-slot", stc8, stc1, $slotset),
+ api_slot("nested-slot", stc9, stc1, $slotset),
+ ],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.slots = ["conditional-slot", "nested-slot", "outer-slot"];
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/complex/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/actual.html
new file mode 100644
index 0000000000..10d0dbb145
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/actual.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/ast.json
new file mode 100644
index 0000000000..c8d8a0ef46
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/ast.json
@@ -0,0 +1,192 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 8,
+ "endColumn": 12,
+ "start": 0,
+ "end": 204,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 8,
+ "startColumn": 1,
+ "endLine": 8,
+ "endColumn": 12,
+ "start": 193,
+ "end": 204
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 10,
+ "name": "condition",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 33,
+ "start": 25,
+ "end": 43
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 4,
+ "endColumn": 16,
+ "start": 15,
+ "end": 106
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 33,
+ "start": 25,
+ "end": 43
+ },
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "conditional-slot",
+ "location": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 46,
+ "start": 53,
+ "end": 90,
+ "startTag": {
+ "startLine": 3,
+ "startColumn": 9,
+ "endLine": 3,
+ "endColumn": 39,
+ "start": 53,
+ "end": 83
+ },
+ "endTag": {
+ "startLine": 3,
+ "startColumn": 39,
+ "endLine": 3,
+ "endColumn": 46,
+ "start": 83,
+ "end": 90
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "conditional-slot"
+ },
+ "location": {
+ "startLine": 3,
+ "startColumn": 15,
+ "endLine": 3,
+ "endColumn": 38,
+ "start": 59,
+ "end": 82
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 5,
+ "startColumn": 5,
+ "endLine": 7,
+ "endColumn": 16,
+ "start": 111,
+ "end": 192
+ },
+ "directiveLocation": {
+ "startLine": 5,
+ "startColumn": 15,
+ "endLine": 5,
+ "endColumn": 23,
+ "start": 121,
+ "end": 129
+ },
+ "children": [
+ {
+ "type": "Slot",
+ "name": "slot",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "slotName": "conditional-slot",
+ "location": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 46,
+ "start": 139,
+ "end": 176,
+ "startTag": {
+ "startLine": 6,
+ "startColumn": 9,
+ "endLine": 6,
+ "endColumn": 39,
+ "start": 139,
+ "end": 169
+ },
+ "endTag": {
+ "startLine": 6,
+ "startColumn": 39,
+ "endLine": 6,
+ "endColumn": 46,
+ "start": 169,
+ "end": 176
+ }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "name": "name",
+ "value": {
+ "type": "Literal",
+ "value": "conditional-slot"
+ },
+ "location": {
+ "startLine": 6,
+ "startColumn": 15,
+ "endLine": 6,
+ "endColumn": 38,
+ "start": 145,
+ "end": 168
+ }
+ }
+ ],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": []
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/expected.js
new file mode 100644
index 0000000000..bbefb416c4
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/expected.js
@@ -0,0 +1,30 @@
+import { registerTemplate } from "lwc";
+const stc0 = {
+ attrs: {
+ name: "conditional-slot",
+ },
+ key: 1,
+};
+const stc1 = [];
+const stc2 = {
+ attrs: {
+ name: "conditional-slot",
+ },
+ key: 2,
+};
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { s: api_slot, fr: api_fragment } = $api;
+ return [
+ $cmp.condition
+ ? api_fragment(0, [api_slot("conditional-slot", stc0, stc1, $slotset)], 0)
+ : api_fragment(
+ 0,
+ [api_slot("conditional-slot", stc2, stc1, $slotset)],
+ 0
+ ),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.slots = ["conditional-slot"];
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/slots/valid-duplicate-slot-names/simple/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/actual.html b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/actual.html
new file mode 100644
index 0000000000..2503d86b7b
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/actual.html
@@ -0,0 +1,12 @@
+
+
+ Conditional Text
+ Happy days!
+
+
+ stranger
+ things
+
+ hello
+ world!
+
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/ast.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/ast.json
new file mode 100644
index 0000000000..de557961a5
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/ast.json
@@ -0,0 +1,359 @@
+{
+ "root": {
+ "type": "Root",
+ "location": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 12,
+ "endColumn": 12,
+ "start": 0,
+ "end": 253,
+ "startTag": {
+ "startLine": 1,
+ "startColumn": 1,
+ "endLine": 1,
+ "endColumn": 11,
+ "start": 0,
+ "end": 10
+ },
+ "endTag": {
+ "startLine": 12,
+ "startColumn": 1,
+ "endLine": 12,
+ "endColumn": 12,
+ "start": 242,
+ "end": 253
+ }
+ },
+ "directives": [],
+ "children": [
+ {
+ "type": "IfBlock",
+ "condition": {
+ "type": "Identifier",
+ "start": 1,
+ "end": 8,
+ "name": "visible",
+ "location": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ }
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 5,
+ "endLine": 5,
+ "endColumn": 16,
+ "start": 15,
+ "end": 112
+ },
+ "directiveLocation": {
+ "startLine": 2,
+ "startColumn": 15,
+ "endLine": 2,
+ "endColumn": 31,
+ "start": 25,
+ "end": 41
+ },
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Conditional Text",
+ "value": {
+ "type": "Literal",
+ "value": "Conditional Text"
+ },
+ "location": {
+ "startLine": 2,
+ "startColumn": 32,
+ "endLine": 4,
+ "endColumn": 9,
+ "start": 42,
+ "end": 76
+ }
+ },
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 4,
+ "endColumn": 29,
+ "start": 76,
+ "end": 96,
+ "startTag": {
+ "startLine": 4,
+ "startColumn": 9,
+ "endLine": 4,
+ "endColumn": 13,
+ "start": 76,
+ "end": 80
+ },
+ "endTag": {
+ "startLine": 4,
+ "startColumn": 24,
+ "endLine": 4,
+ "endColumn": 29,
+ "start": 91,
+ "end": 96
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "Happy days!",
+ "value": {
+ "type": "Literal",
+ "value": "Happy days!"
+ },
+ "location": {
+ "startLine": 4,
+ "startColumn": 13,
+ "endLine": 4,
+ "endColumn": 24,
+ "start": 80,
+ "end": 91
+ }
+ }
+ ]
+ }
+ ],
+ "else": {
+ "type": "ElseBlock",
+ "location": {
+ "startLine": 6,
+ "startColumn": 5,
+ "endLine": 9,
+ "endColumn": 16,
+ "start": 117,
+ "end": 202
+ },
+ "directiveLocation": {
+ "startLine": 6,
+ "startColumn": 15,
+ "endLine": 6,
+ "endColumn": 23,
+ "start": 127,
+ "end": 135
+ },
+ "children": [
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 7,
+ "startColumn": 9,
+ "endLine": 7,
+ "endColumn": 26,
+ "start": 145,
+ "end": 162,
+ "startTag": {
+ "startLine": 7,
+ "startColumn": 9,
+ "endLine": 7,
+ "endColumn": 13,
+ "start": 145,
+ "end": 149
+ },
+ "endTag": {
+ "startLine": 7,
+ "startColumn": 21,
+ "endLine": 7,
+ "endColumn": 26,
+ "start": 157,
+ "end": 162
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "stranger",
+ "value": {
+ "type": "Literal",
+ "value": "stranger"
+ },
+ "location": {
+ "startLine": 7,
+ "startColumn": 13,
+ "endLine": 7,
+ "endColumn": 21,
+ "start": 149,
+ "end": 157
+ }
+ }
+ ]
+ },
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 8,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 24,
+ "start": 171,
+ "end": 186,
+ "startTag": {
+ "startLine": 8,
+ "startColumn": 9,
+ "endLine": 8,
+ "endColumn": 13,
+ "start": 171,
+ "end": 175
+ },
+ "endTag": {
+ "startLine": 8,
+ "startColumn": 19,
+ "endLine": 8,
+ "endColumn": 24,
+ "start": 181,
+ "end": 186
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "things",
+ "value": {
+ "type": "Literal",
+ "value": "things"
+ },
+ "location": {
+ "startLine": 8,
+ "startColumn": 13,
+ "endLine": 8,
+ "endColumn": 19,
+ "start": 175,
+ "end": 181
+ }
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 10,
+ "startColumn": 5,
+ "endLine": 10,
+ "endColumn": 19,
+ "start": 207,
+ "end": 221,
+ "startTag": {
+ "startLine": 10,
+ "startColumn": 5,
+ "endLine": 10,
+ "endColumn": 9,
+ "start": 207,
+ "end": 211
+ },
+ "endTag": {
+ "startLine": 10,
+ "startColumn": 14,
+ "endLine": 10,
+ "endColumn": 19,
+ "start": 216,
+ "end": 221
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "hello",
+ "value": {
+ "type": "Literal",
+ "value": "hello"
+ },
+ "location": {
+ "startLine": 10,
+ "startColumn": 9,
+ "endLine": 10,
+ "endColumn": 14,
+ "start": 211,
+ "end": 216
+ }
+ }
+ ]
+ },
+ {
+ "type": "Element",
+ "name": "h1",
+ "namespace": "http://www.w3.org/1999/xhtml",
+ "location": {
+ "startLine": 11,
+ "startColumn": 5,
+ "endLine": 11,
+ "endColumn": 20,
+ "start": 226,
+ "end": 241,
+ "startTag": {
+ "startLine": 11,
+ "startColumn": 5,
+ "endLine": 11,
+ "endColumn": 9,
+ "start": 226,
+ "end": 230
+ },
+ "endTag": {
+ "startLine": 11,
+ "startColumn": 15,
+ "endLine": 11,
+ "endColumn": 20,
+ "start": 236,
+ "end": 241
+ }
+ },
+ "attributes": [],
+ "properties": [],
+ "directives": [],
+ "listeners": [],
+ "children": [
+ {
+ "type": "Text",
+ "raw": "world!",
+ "value": {
+ "type": "Literal",
+ "value": "world!"
+ },
+ "location": {
+ "startLine": 11,
+ "startColumn": 9,
+ "endLine": 11,
+ "endColumn": 15,
+ "start": 230,
+ "end": 236
+ }
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/expected.js b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/expected.js
new file mode 100644
index 0000000000..b4f68c716b
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/expected.js
@@ -0,0 +1,30 @@
+import { parseFragment, registerTemplate } from "lwc";
+const $fragment1 = parseFragment`Happy days!
`;
+const $fragment2 = parseFragment`stranger
`;
+const $fragment3 = parseFragment`things
`;
+const $fragment4 = parseFragment`hello
`;
+const $fragment5 = parseFragment`world!
`;
+function tmpl($api, $cmp, $slotset, $ctx) {
+ const { t: api_text, st: api_static_fragment, fr: api_fragment } = $api;
+ return [
+ $cmp.visible
+ ? api_fragment(
+ 0,
+ [api_text("Conditional Text"), api_static_fragment($fragment1(), 2)],
+ 0
+ )
+ : api_fragment(
+ 0,
+ [
+ api_static_fragment($fragment2(), 4),
+ api_static_fragment($fragment3(), 6),
+ ],
+ 0
+ ),
+ api_static_fragment($fragment4(), 8),
+ api_static_fragment($fragment5(), 10),
+ ];
+ /*LWC compiler vX.X.X*/
+}
+export default registerTemplate(tmpl);
+tmpl.stylesheets = [];
diff --git a/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/metadata.json b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/metadata.json
new file mode 100644
index 0000000000..51ec5f799c
--- /dev/null
+++ b/packages/@lwc/template-compiler/src/__tests__/fixtures/directive-lwc-if-else/with-siblings/metadata.json
@@ -0,0 +1,3 @@
+{
+ "warnings": []
+}
\ No newline at end of file
diff --git a/packages/@lwc/template-compiler/src/codegen/helpers.ts b/packages/@lwc/template-compiler/src/codegen/helpers.ts
index e2c19326de..c4adb37308 100644
--- a/packages/@lwc/template-compiler/src/codegen/helpers.ts
+++ b/packages/@lwc/template-compiler/src/codegen/helpers.ts
@@ -6,7 +6,14 @@
*/
import * as t from '../shared/estree';
import { toPropertyName } from '../shared/utils';
-import { BaseElement, ChildNode, LWCDirectiveRenderMode, Node, Root } from '../shared/types';
+import {
+ BaseElement,
+ ChildNode,
+ LWCDirectiveRenderMode,
+ Node,
+ ParentNode,
+ Root,
+} from '../shared/types';
import {
isParentNode,
isSlot,
@@ -16,6 +23,8 @@ import {
isElement,
isText,
isComment,
+ isIfBlock,
+ isConditionalParentBlock,
} from '../shared/ast';
import { TEMPLATE_FUNCTION_NAME, TEMPLATE_PARAMS } from '../shared/constants';
@@ -53,32 +62,45 @@ export function objectToAST(
);
}
-export function containsDynamicChildren(children: ChildNode[]): boolean {
- return children.some((child) => {
- if (isForBlock(child) || isIf(child)) {
- return containsDynamicChildren(child.children);
+export function containsDynamicChildren(parent: ParentNode): boolean {
+ const hasDynamicChildren = parent.children.some((child) => {
+ // The child in the children array will only ever contain an IfBlock.
+ // ElseIfBlock and ElseBlock are chained together starting from the IfBlock.
+ if (isForBlock(child) || isIf(child) || isIfBlock(child)) {
+ return containsDynamicChildren(child);
}
return false;
});
+
+ // In order to check the if-elseif-else chain fully, if the parent is an IfBlock or ElseIfBlock
+ // the else branch must be checked as well.
+ const elseConditionHasDynamicChildren =
+ isConditionalParentBlock(parent) && parent.else
+ ? containsDynamicChildren(parent.else)
+ : false;
+
+ return hasDynamicChildren || elseConditionHasDynamicChildren;
}
/**
* Returns true if the children should be flattened.
*
- * Children should be flattened if they contain an iterator,
- * a dynamic directive or a slot inside a light dom element.
+ * This function searches through the children to determine if flattening needs to occur in the runtime.
+ * Children should be flattened if they contain an iterator, a dynamic directive or a slot inside a light dom element.
*/
export function shouldFlatten(codeGen: CodeGen, children: ChildNode[]): boolean {
- return children.some(
- (child) =>
+ return children.some((child) => {
+ return (
+ // ForBlock will generate a list of iterable vnodes
isForBlock(child) ||
- (isParentNode(child) &&
- // If node is only a control flow node and does not map to a stand alone element.
- // Search children to determine if it should be flattened.
- ((isIf(child) && shouldFlatten(codeGen, child.children)) ||
- (codeGen.renderMode === LWCDirectiveRenderMode.light && isSlot(child))))
- );
+ // light DOM slots
+ (isSlot(child) && codeGen.renderMode === LWCDirectiveRenderMode.light) ||
+ // If node is only a control flow node and does not map to a stand alone element.
+ // Search children to determine if it should be flattened.
+ (isIf(child) && shouldFlatten(codeGen, child.children))
+ );
+ });
}
/**
@@ -264,13 +286,18 @@ function collectStaticNodes(node: ChildNode, staticNodes: Set, state:
} else if (isComment(node)) {
nodeIsStatic = true;
} else {
- // it is ForBlock | If | BaseElement
+ // it is ElseBlock | ForBlock | If | BaseElement
node.children.forEach((childNode) => {
collectStaticNodes(childNode, staticNodes, state);
childrenAreStatic = childrenAreStatic && staticNodes.has(childNode);
});
+ // for IfBlock and ElseifBlock, traverse down the else branch
+ if (isConditionalParentBlock(node) && node.else) {
+ collectStaticNodes(node.else, staticNodes, state);
+ }
+
nodeIsStatic =
isBaseElement(node) && !isCustomRendererHookRequired(node, state) && isStaticNode(node);
}
diff --git a/packages/@lwc/template-compiler/src/codegen/index.ts b/packages/@lwc/template-compiler/src/codegen/index.ts
index aeceea3dd0..6c0bf14f11 100644
--- a/packages/@lwc/template-compiler/src/codegen/index.ts
+++ b/packages/@lwc/template-compiler/src/codegen/index.ts
@@ -16,6 +16,7 @@ import {
isStringLiteral,
isForBlock,
isIf,
+ isIfBlock,
isForEach,
isBaseElement,
isExpression,
@@ -28,6 +29,7 @@ import {
isRefDirective,
isSpreadDirective,
isElement,
+ isElseifBlock,
} from '../shared/ast';
import { TEMPLATE_PARAMS, TEMPLATE_FUNCTION_NAME, RENDERER } from '../shared/constants';
import {
@@ -36,6 +38,7 @@ import {
ChildNode,
Text,
If,
+ IfBlock,
ForBlock,
ForEach,
Attribute,
@@ -43,6 +46,7 @@ import {
Comment,
ForOf,
BaseElement,
+ ElseifBlock,
} from '../shared/types';
import * as t from '../shared/estree';
import {
@@ -154,11 +158,13 @@ function transform(codeGen: CodeGen): t.Expression {
res.push(transformElement(child, slotParentName));
} else if (isComment(child) && codeGen.preserveComments) {
res.push(transformComment(child));
+ } else if (isIfBlock(child)) {
+ res.push(transformConditionalParentBlock(child));
}
}
if (shouldFlatten(codeGen, children)) {
- if (children.length === 1 && !containsDynamicChildren(children)) {
+ if (children.length === 1 && !containsDynamicChildren(parent)) {
return res[0];
} else {
return codeGen.genFlatten([t.arrayExpression(res)]);
@@ -197,6 +203,41 @@ function transform(codeGen: CodeGen): t.Expression {
return res;
}
+ /**
+ * Transforms an IfBlock or ElseifBlock along with both its direct descendants and its 'else' descendants.
+ *
+ * @param conditionalParentBlock The IfBlock or ElseifBlock to transform into a conditional expression
+ * @param key The key to use for this chain of IfBlock/ElseifBlock branches, if applicable
+ * @returns A conditional expression representing the full conditional tree with conditionalParentBlock as the root node
+ */
+ function transformConditionalParentBlock(
+ conditionalParentBlock: IfBlock | ElseifBlock,
+ key?: number
+ ): t.Expression {
+ const ifBlockKey = key ?? codeGen.generateKey();
+
+ const childrenExpression = codeGen.genFragment(
+ t.literal(ifBlockKey),
+ transformChildren(conditionalParentBlock)
+ );
+
+ let elseExpression: t.Expression = t.literal(null);
+ if (conditionalParentBlock.else) {
+ elseExpression = isElseifBlock(conditionalParentBlock.else)
+ ? transformConditionalParentBlock(conditionalParentBlock.else, ifBlockKey)
+ : codeGen.genFragment(
+ t.literal(ifBlockKey),
+ transformChildren(conditionalParentBlock.else)
+ );
+ }
+
+ return t.conditionalExpression(
+ codeGen.bindExpression(conditionalParentBlock.condition),
+ childrenExpression,
+ elseExpression
+ );
+ }
+
function applyInlineIf(
ifNode: If,
node: t.Expression,
diff --git a/packages/@lwc/template-compiler/src/parser/index.ts b/packages/@lwc/template-compiler/src/parser/index.ts
index 082a11d1ab..56f1ac7d9a 100644
--- a/packages/@lwc/template-compiler/src/parser/index.ts
+++ b/packages/@lwc/template-compiler/src/parser/index.ts
@@ -30,6 +30,9 @@ import {
LWCDirectiveRenderMode,
LWCDirectiveDomMode,
If,
+ IfBlock,
+ ElseBlock,
+ ElseifBlock,
Property,
ElementDirectiveName,
RootDirectiveName,
@@ -253,13 +256,18 @@ function parseElementDirectives(
): ParentNode | undefined {
let current: ParentNode | undefined;
- const parsers = [parseForEach, parseForOf, parseIf];
+ const parsers = [
+ parseIfBlock,
+ parseElseifBlock,
+ parseElseBlock,
+ parseForEach,
+ parseForOf,
+ parseIf,
+ ];
for (const parser of parsers) {
const prev = current || parent;
- const node = parser(ctx, parsedAttr, parse5ElmLocation);
+ const node = parser(ctx, parsedAttr, parse5ElmLocation, prev);
if (node) {
- ctx.addNodeCurrentScope(node);
- prev.children.push(node);
current = node;
}
}
@@ -291,7 +299,7 @@ function parseBaseElement(
}
if (element) {
- ctx.addNodeCurrentScope(element);
+ ctx.addNodeCurrentElementScope(element);
parent.children.push(element);
}
@@ -306,21 +314,43 @@ function parseChildren(
): void {
const children = (parse5Utils.getTemplateContent(parse5Parent) ?? parse5Parent).childNodes;
+ ctx.beginSiblingScope();
for (const child of children) {
ctx.withErrorRecovery(() => {
if (parse5Utils.isElementNode(child)) {
- ctx.beginScope();
+ ctx.beginElementScope();
parseElement(ctx, child, parent, parse5ParentLocation);
- ctx.endScope();
+
+ // If we're parsing a chain of if/elseif/else nodes, any node other than
+ // an else-if node ends the chain.
+ const node = ctx.endElementScope();
+ if (
+ node &&
+ ctx.isParsingSiblingIfBlock() &&
+ !ast.isIfBlock(node) &&
+ !ast.isElseifBlock(node)
+ ) {
+ ctx.endIfChain();
+ }
} else if (parse5Utils.isTextNode(child)) {
const textNodes = parseText(ctx, child);
parent.children.push(...textNodes);
+ // Non whitespace text nodes end any if chain we may be parsing
+ if (ctx.isParsingSiblingIfBlock() && textNodes.length > 0) {
+ ctx.endIfChain();
+ }
} else if (parse5Utils.isCommentNode(child)) {
const commentNode = parseComment(child);
parent.children.push(commentNode);
+ // If preserveComments is enabled, comments become syntactically meaningful and
+ // end any if chain we may be parsing
+ if (ctx.isParsingSiblingIfBlock() && ctx.preserveComments) {
+ ctx.endIfChain();
+ }
}
});
}
+ ctx.endSiblingScope();
}
function parseText(ctx: ParserCtx, parse5Text: parse5.TextNode): Text[] {
@@ -442,13 +472,24 @@ function applyHandlers(ctx: ParserCtx, parsedAttr: ParsedAttribute, element: Bas
function parseIf(
ctx: ParserCtx,
parsedAttr: ParsedAttribute,
- parse5ElmLocation: parse5.ElementLocation
+ parse5ElmLocation: parse5.ElementLocation,
+ parent: ParentNode
): If | undefined {
const ifAttribute = parsedAttr.pick(IF_RE);
if (!ifAttribute) {
return;
}
+ // if:true cannot be used with lwc:if, lwc:elseif, lwc:else
+ const incompatibleDirective = ctx.findInCurrentElementScope(ast.isConditionalBlock);
+ if (incompatibleDirective) {
+ ctx.throwAtLocation(
+ ParserDiagnostics.LWC_IF_CANNOT_BE_USED_WITH_IF_DIRECTIVE,
+ ast.sourceLocation(parse5ElmLocation),
+ [ifAttribute.name]
+ );
+ }
+
if (!ast.isExpression(ifAttribute.value)) {
ctx.throwOnNode(ParserDiagnostics.IF_DIRECTIVE_SHOULD_BE_EXPRESSION, ifAttribute);
}
@@ -458,12 +499,167 @@ function parseIf(
ctx.throwOnNode(ParserDiagnostics.UNEXPECTED_IF_MODIFIER, ifAttribute, [modifier]);
}
- return ast.ifNode(
+ const node = ast.ifNode(
modifier,
ifAttribute.value,
ast.sourceLocation(parse5ElmLocation),
ifAttribute.location
);
+
+ ctx.addNodeCurrentElementScope(node);
+ parent.children.push(node);
+
+ return node;
+}
+
+function parseIfBlock(
+ ctx: ParserCtx,
+ parsedAttr: ParsedAttribute,
+ parse5ElmLocation: parse5.ElementLocation,
+ parent: ParentNode
+): IfBlock | undefined {
+ const ifBlockAttribute = parsedAttr.pick('lwc:if');
+ if (!ifBlockAttribute) {
+ return;
+ }
+
+ if (!ast.isExpression(ifBlockAttribute.value)) {
+ ctx.throwOnNode(
+ ParserDiagnostics.IF_BLOCK_DIRECTIVE_SHOULD_BE_EXPRESSION,
+ ifBlockAttribute
+ );
+ }
+
+ // An if block always starts a new chain.
+ if (ctx.isParsingSiblingIfBlock()) {
+ ctx.endIfChain();
+ }
+
+ const ifNode = ast.ifBlockNode(
+ ifBlockAttribute.value,
+ ast.sourceLocation(parse5ElmLocation),
+ ifBlockAttribute.location
+ );
+
+ ctx.addNodeCurrentElementScope(ifNode);
+ ctx.beginIfChain(ifNode);
+ parent.children.push(ifNode);
+
+ return ifNode;
+}
+
+function parseElseifBlock(
+ ctx: ParserCtx,
+ parsedAttr: ParsedAttribute,
+ parse5ElmLocation: parse5.ElementLocation,
+ _: ParentNode
+): ElseifBlock | undefined {
+ const elseifBlockAttribute = parsedAttr.pick('lwc:elseif');
+ if (!elseifBlockAttribute) {
+ return;
+ }
+
+ const hasIfBlock = ctx.findInCurrentElementScope(ast.isIfBlock);
+ if (hasIfBlock) {
+ ctx.throwAtLocation(
+ ParserDiagnostics.INVALID_IF_BLOCK_DIRECTIVE_WITH_CONDITIONAL,
+ ast.sourceLocation(parse5ElmLocation),
+ [elseifBlockAttribute.name]
+ );
+ }
+
+ if (!ast.isExpression(elseifBlockAttribute.value)) {
+ ctx.throwOnNode(
+ ParserDiagnostics.ELSEIF_BLOCK_DIRECTIVE_SHOULD_BE_EXPRESSION,
+ elseifBlockAttribute
+ );
+ }
+
+ const conditionalParent = ctx.getSiblingIfNode();
+ if (!conditionalParent || !ast.isConditionalParentBlock(conditionalParent)) {
+ ctx.throwAtLocation(
+ ParserDiagnostics.LWC_IF_SCOPE_NOT_FOUND,
+ ast.sourceLocation(parse5ElmLocation),
+ [elseifBlockAttribute.name]
+ );
+ }
+
+ const elseifNode = ast.elseifBlockNode(
+ elseifBlockAttribute.value,
+ ast.sourceLocation(parse5ElmLocation),
+ elseifBlockAttribute.location
+ );
+
+ // Attach the node as a child of the preceding IfBlock
+ ctx.addNodeCurrentElementScope(elseifNode);
+ ctx.appendToIfChain(elseifNode);
+ conditionalParent.else = elseifNode;
+
+ return elseifNode;
+}
+
+function parseElseBlock(
+ ctx: ParserCtx,
+ parsedAttr: ParsedAttribute,
+ parse5ElmLocation: parse5.ElementLocation,
+ _: ParentNode
+): ElseBlock | undefined {
+ const elseBlockAttribute = parsedAttr.pick('lwc:else');
+ if (!elseBlockAttribute) {
+ return;
+ }
+
+ // Cannot be used with lwc:if on the same element
+ const hasIfBlock = ctx.findInCurrentElementScope(ast.isIfBlock);
+ if (hasIfBlock) {
+ ctx.throwAtLocation(
+ ParserDiagnostics.INVALID_IF_BLOCK_DIRECTIVE_WITH_CONDITIONAL,
+ ast.sourceLocation(parse5ElmLocation),
+ [elseBlockAttribute.name]
+ );
+ }
+
+ // Cannot be used with lwc:elseif on the same element
+ const hasElseifBlock = ctx.findInCurrentElementScope(ast.isElseifBlock);
+ if (hasElseifBlock) {
+ ctx.throwAtLocation(
+ ParserDiagnostics.INVALID_ELSEIF_BLOCK_DIRECTIVE_WITH_CONDITIONAL,
+ ast.sourceLocation(parse5ElmLocation),
+ [elseBlockAttribute.name]
+ );
+ }
+
+ // Must be used immediately after an lwc:if or lwc:elseif
+ const conditionalParent = ctx.getSiblingIfNode();
+ if (!conditionalParent || !ast.isConditionalParentBlock(conditionalParent)) {
+ ctx.throwAtLocation(
+ ParserDiagnostics.LWC_IF_SCOPE_NOT_FOUND,
+ ast.sourceLocation(parse5ElmLocation),
+ [elseBlockAttribute.name]
+ );
+ }
+
+ // Must not have a value
+ if (!ast.isBooleanLiteral(elseBlockAttribute.value)) {
+ ctx.throwAtLocation(
+ ParserDiagnostics.ELSE_BLOCK_DIRECTIVE_CANNOT_HAVE_VALUE,
+ ast.sourceLocation(parse5ElmLocation)
+ );
+ }
+
+ const elseNode = ast.elseBlockNode(
+ ast.sourceLocation(parse5ElmLocation),
+ elseBlockAttribute.location
+ );
+
+ // Attach the node as a child of the preceding IfBlock
+ ctx.addNodeCurrentElementScope(elseNode);
+
+ // Avoid ending the if-chain until we finish parsing all children
+ ctx.appendToIfChain(elseNode);
+ conditionalParent.else = elseNode;
+
+ return elseNode;
}
function applyRootLwcDirectives(ctx: ParserCtx, parsedAttr: ParsedAttribute, root: Root): void {
@@ -721,7 +917,8 @@ function applyRefDirective(
function parseForEach(
ctx: ParserCtx,
parsedAttr: ParsedAttribute,
- parse5ElmLocation: parse5.ElementLocation
+ parse5ElmLocation: parse5.ElementLocation,
+ parent: ParentNode
): ForEach | undefined {
const forEachAttribute = parsedAttr.pick('for:each');
const forItemAttribute = parsedAttr.pick('for:item');
@@ -755,13 +952,18 @@ function parseForEach(
index = parseIdentifier(ctx, forIndexValue.value, forIndex.location);
}
- return ast.forEach(
+ const node = ast.forEach(
forEachAttribute.value,
ast.sourceLocation(parse5ElmLocation),
forEachAttribute.location,
item,
index
);
+
+ ctx.addNodeCurrentElementScope(node);
+ parent.children.push(node);
+
+ return node;
} else if (forEachAttribute || forItemAttribute) {
ctx.throwAtLocation(
ParserDiagnostics.FOR_EACH_AND_FOR_ITEM_DIRECTIVES_SHOULD_BE_TOGETHER,
@@ -773,14 +975,15 @@ function parseForEach(
function parseForOf(
ctx: ParserCtx,
parsedAttr: ParsedAttribute,
- parse5ElmLocation: parse5.ElementLocation
+ parse5ElmLocation: parse5.ElementLocation,
+ parent: ParentNode
): ForOf | undefined {
const iteratorExpression = parsedAttr.pick(ITERATOR_RE);
if (!iteratorExpression) {
return;
}
- const hasForEach = ctx.findSibling(ast.isForEach);
+ const hasForEach = ctx.findInCurrentElementScope(ast.isForEach);
if (hasForEach) {
ctx.throwAtLocation(
ParserDiagnostics.INVALID_FOR_EACH_WITH_ITERATOR,
@@ -800,12 +1003,17 @@ function parseForOf(
const iterator = parseIdentifier(ctx, iteratorName, iteratorExpression.location);
- return ast.forOf(
+ const node = ast.forOf(
iteratorExpression.value,
iterator,
ast.sourceLocation(parse5ElmLocation),
iteratorExpression.location
);
+
+ ctx.addNodeCurrentElementScope(node);
+ parent.children.push(node);
+
+ return node;
}
function applyKey(ctx: ParserCtx, parsedAttr: ParsedAttribute, element: BaseElement): void {
@@ -856,7 +1064,7 @@ function parseSlot(
): Slot {
const location = ast.sourceLocation(parse5ElmLocation);
- const hasDirectives = ctx.findSibling(ast.isForBlock) || ctx.findSibling(ast.isIf);
+ const hasDirectives = ctx.findInCurrentElementScope(ast.isElementDirective);
if (hasDirectives) {
ctx.throwAtLocation(ParserDiagnostics.SLOT_TAG_CANNOT_HAVE_DIRECTIVES, location);
}
@@ -897,8 +1105,8 @@ function parseSlot(
}
}
- const alreadySeen = ctx.seenSlots.has(name);
- ctx.seenSlots.add(name);
+ const alreadySeen = ctx.hasSeenSlot(name);
+ ctx.addSeenSlot(name);
if (alreadySeen) {
ctx.warnAtLocation(ParserDiagnostics.NO_DUPLICATE_SLOTS, location, [
diff --git a/packages/@lwc/template-compiler/src/parser/parser.ts b/packages/@lwc/template-compiler/src/parser/parser.ts
index 81dfc05b5c..545f5d3a48 100644
--- a/packages/@lwc/template-compiler/src/parser/parser.ts
+++ b/packages/@lwc/template-compiler/src/parser/parser.ts
@@ -22,6 +22,9 @@ import {
ParentNode,
BaseNode,
LWCDirectiveRenderMode,
+ IfBlock,
+ ElseifBlock,
+ ElseBlock,
} from '../shared/types';
function normalizeLocation(location?: SourceLocation): Location {
@@ -45,6 +48,30 @@ interface ParentWrapper {
current: ParentNode;
}
+interface IfContext {
+ currentNode: IfBlock | ElseifBlock | ElseBlock;
+
+ // Within a specific if-context, each set of seen slot names must be tracked separately
+ // because duplicate names in separate branches of the same if-block are allowed (the branching
+ // logic provides a compile-time guarantee that the slots will not be rendered multiple times).
+ // seenSlots keeps track of each set holding the slots seen in each branch of the if-block.
+ seenSlots: Set[];
+}
+
+// A SiblingScope object keeps track of the context needed to parse a series of if-elseif-else nodes.
+interface SiblingScope {
+ // Context for the if-elseif-else chain currently being parsed at this level. This
+ // IfContext keeps track of the most recently parsed node in the chain and the set of slot names we've seen in all
+ // previous siblings in the chain.
+ ifContext?: IfContext;
+
+ // Reference to the nearest ancestor IfContext. The existence of an ancestor
+ // IfContext means that we are currently parsing nodes nested within an if-elseif-else chain. Context from that ancestor
+ // is needed to track which slot names have already been seen in and only in the current scope. This reference is also needed
+ // so we know where to merge all visited slot names from the current IfContext.
+ ancestorIfContext?: IfContext;
+}
+
export default class ParserCtx {
private readonly source: String;
@@ -55,17 +82,23 @@ export default class ParserCtx {
readonly seenSlots: Set = new Set();
/**
- * Scopes keep track of the hierarchy of ParentNodes as the parser traverses the parse5 AST.
- * Each scope is represented by an array where each node in the array correspond to either
- * a ForEach, ForOf, If, Element, Component, or Slot.
+ * 'elementScopes' keeps track of the hierarchy of ParentNodes as the parser
+ * traverses the parse5 AST. Each 'elementScope' is an array where each node in
+ * the array corresponds to either an IfBlock, ElseifBlock, ElseBlock, ForEach, ForOf, If, Element, Component, or Slot.
*
- * Currently, each scope has a hierarchy of ForBlock > IfBlock > Element | Component | Slot.
- * Note: Not all scopes will have all three, but when they do, they will appear in this order.
+ * Currently, each elementScope has a hierarchy of IfBlock > ForBlock > If > Element | Component | Slot.
+ * Note: Not all elementScopes will have all the nodes listed above, but when they do, they will appear in this order.
* We do not keep track of template nodes.
*
* Each scope corresponds to the original parse5.Element node.
*/
- private readonly scopes: ParentNode[][] = [];
+ private readonly elementScopes: ParentNode[][] = [];
+
+ /**
+ * 'siblingScopes' keeps track of the context from one sibling node to another.
+ * This holds the info needed to properly parse lwc:if, lwc:elseif, and lwc:else directives.
+ */
+ private readonly siblingScopes: SiblingScope[] = [];
renderMode: LWCDirectiveRenderMode;
preserveComments: boolean;
@@ -92,7 +125,7 @@ export default class ParserCtx {
* This method flattens the scopes into a single array for traversal.
*/
*ancestors(element?: ParentNode): IterableIterator {
- const ancestors = ([] as ParentNode[]).concat(...this.scopes);
+ const ancestors = this.elementScopes.flat();
const start = element ? ancestors.indexOf(element) : ancestors.length - 1;
for (let i = start; i >= 0; i--) {
@@ -134,33 +167,138 @@ export default class ParserCtx {
* @param {function} predicate - This callback is called once for each sibling in the current scope
* until it finds one where predicate returns true.
*/
- findSibling(predicate: (node: ParentNode) => node is A): A | null {
- const currentScope = this.currentScope() || [];
- const sibling = currentScope.find(predicate);
- return sibling || null;
+ findInCurrentElementScope(
+ predicate: (node: ParentNode) => node is A
+ ): A | null {
+ const currentScope = this.currentElementScope() || [];
+ return currentScope.find(predicate) || null;
}
- beginScope(): void {
- this.scopes.push([]);
+ beginElementScope(): void {
+ this.elementScopes.push([]);
}
- endScope(): void {
- this.scopes.pop();
+ endElementScope(): ParentNode | undefined {
+ const scope = this.elementScopes.pop();
+ return scope ? scope[0] : undefined;
}
- addNodeCurrentScope(node: ParentNode): void {
- const currentScope = this.currentScope();
+ addNodeCurrentElementScope(node: ParentNode): void {
+ const currentScope = this.currentElementScope();
/* istanbul ignore if */
if (!currentScope) {
- throw new Error("Can't invoke addNodeCurrentScope if there is no current scope");
+ throw new Error("Can't invoke addNodeCurrentElementScope if there is no current scope");
}
currentScope.push(node);
}
- private currentScope(): ParentNode[] | undefined {
- return this.scopes[this.scopes.length - 1];
+ hasSeenSlot(name: string): boolean {
+ return this.seenSlotsFromAncestorIfTree().has(name);
+ }
+
+ addSeenSlot(name: string): void {
+ const currentSeenSlots = this.seenSlotsFromAncestorIfTree();
+ if (currentSeenSlots) {
+ currentSeenSlots.add(name);
+ } else {
+ this.seenSlots.add(name);
+ }
+ }
+
+ private currentElementScope(): ParentNode[] | undefined {
+ return this.elementScopes[this.elementScopes.length - 1];
+ }
+
+ beginSiblingScope() {
+ this.siblingScopes.push({
+ ancestorIfContext: this.currentIfContext() || this.ancestorIfContext(),
+ });
+ }
+
+ endSiblingScope() {
+ this.siblingScopes.pop();
+ }
+
+ beginIfChain(node: IfBlock) {
+ const currentSiblingContext = this.currentSiblingContext();
+ if (!currentSiblingContext) {
+ throw new Error('Cannot invoke beginIfChain if there is currently no sibling context');
+ }
+
+ const currentIfContext = this.currentIfContext();
+ if (currentIfContext) {
+ throw new Error(
+ 'Should not invoke beginIfChain if an if context already exists. First end the current chain before starting a new one.'
+ );
+ }
+
+ const previouslySeenSlots = this.seenSlotsFromAncestorIfTree();
+ currentSiblingContext.ifContext = {
+ currentNode: node,
+ seenSlots: [new Set(previouslySeenSlots)],
+ };
+ }
+
+ appendToIfChain(node: ElseifBlock | ElseBlock) {
+ const currentIfContext = this.currentIfContext();
+ if (!currentIfContext) {
+ throw new Error('Cannot invoke appendToIfChain without first setting the if context.');
+ }
+
+ currentIfContext.currentNode = node;
+
+ const previouslySeenSlots = this.seenSlotsFromAncestorIfTree();
+ currentIfContext.seenSlots.push(new Set(previouslySeenSlots));
+ }
+
+ endIfChain() {
+ const currentIfContext = this.currentIfContext();
+ if (!currentIfContext) {
+ throw new Error('Cannot invoke endIfChain if there is currently no if context');
+ }
+
+ // Merge seen slot names from the current if chain into the parent scope.
+ const seenSlotsInAncestorIfTree = this.seenSlotsFromAncestorIfTree();
+ for (const seenSlots of currentIfContext.seenSlots) {
+ for (const name of seenSlots) {
+ seenSlotsInAncestorIfTree.add(name);
+ }
+ }
+
+ const currentSiblingContext = this.currentSiblingContext();
+ if (currentSiblingContext) {
+ currentSiblingContext.ifContext = undefined;
+ }
+ }
+
+ getSiblingIfNode(): IfBlock | ElseifBlock | ElseBlock | undefined {
+ return this.currentIfContext()?.currentNode;
+ }
+
+ isParsingSiblingIfBlock(): boolean {
+ return !!this.currentIfContext();
+ }
+
+ private currentSiblingContext(): SiblingScope | undefined {
+ return this.siblingScopes[this.siblingScopes.length - 1];
+ }
+
+ private currentIfContext(): IfContext | undefined {
+ return this.currentSiblingContext()?.ifContext;
+ }
+
+ private ancestorIfContext(): IfContext | undefined {
+ return this.currentSiblingContext()?.ancestorIfContext;
+ }
+
+ private seenSlotsFromAncestorIfTree(): Set {
+ const ancestorIfContext = this.ancestorIfContext();
+ if (ancestorIfContext) {
+ return ancestorIfContext.seenSlots[ancestorIfContext.seenSlots.length - 1];
+ }
+ return this.seenSlots;
}
/**
diff --git a/packages/@lwc/template-compiler/src/shared/ast.ts b/packages/@lwc/template-compiler/src/shared/ast.ts
index 118e567619..aff748411c 100644
--- a/packages/@lwc/template-compiler/src/shared/ast.ts
+++ b/packages/@lwc/template-compiler/src/shared/ast.ts
@@ -33,6 +33,9 @@ import {
ForOf,
LWCDirectiveRenderMode,
If,
+ IfBlock,
+ ElseBlock,
+ ElseifBlock,
ElementSourceLocation,
InnerHTMLDirective,
BaseElement,
@@ -205,6 +208,46 @@ export function ifNode(
};
}
+export function ifBlockNode(
+ condition: Expression,
+ elementLocation: SourceLocation,
+ directiveLocation: SourceLocation
+): IfBlock {
+ return {
+ type: 'IfBlock',
+ condition,
+ location: elementLocation,
+ directiveLocation,
+ children: [],
+ };
+}
+
+export function elseifBlockNode(
+ condition: Expression,
+ elementLocation: SourceLocation,
+ directiveLocation: SourceLocation
+): ElseifBlock {
+ return {
+ type: 'ElseifBlock',
+ condition,
+ location: elementLocation,
+ directiveLocation,
+ children: [],
+ };
+}
+
+export function elseBlockNode(
+ elementLocation: SourceLocation,
+ directiveLocation: SourceLocation
+): ElseBlock {
+ return {
+ type: 'ElseBlock',
+ location: elementLocation,
+ directiveLocation,
+ children: [],
+ };
+}
+
export function eventListener(
name: string,
handler: Expression,
@@ -386,6 +429,32 @@ export function isIf(node: BaseNode): node is If {
return node.type === 'If';
}
+export function isIfBlock(node: BaseNode): node is IfBlock {
+ return node.type === 'IfBlock';
+}
+
+export function isElseifBlock(node: BaseNode): node is ElseifBlock {
+ return node.type === 'ElseifBlock';
+}
+
+export function isElseBlock(node: BaseNode): node is ElseBlock {
+ return node.type === 'ElseBlock';
+}
+
+export function isConditionalParentBlock(node: BaseNode): node is IfBlock | ElseifBlock {
+ return isIfBlock(node) || isElseifBlock(node);
+}
+
+export function isConditionalBlock(node: BaseNode): node is IfBlock | ElseifBlock | ElseBlock {
+ return isIfBlock(node) || isElseifBlock(node) || isElseBlock(node);
+}
+
+export function isElementDirective(
+ node: BaseNode
+): node is IfBlock | ElseifBlock | ElseBlock | ForBlock | If {
+ return isConditionalBlock(node) || isForBlock(node) || isIf(node);
+}
+
export function isParentNode(node: BaseNode): node is ParentNode {
return isBaseElement(node) || isRoot(node) || isForBlock(node) || isIf(node);
}
diff --git a/packages/@lwc/template-compiler/src/shared/types.ts b/packages/@lwc/template-compiler/src/shared/types.ts
index 57c2f5c6f8..c97baae7c3 100644
--- a/packages/@lwc/template-compiler/src/shared/types.ts
+++ b/packages/@lwc/template-compiler/src/shared/types.ts
@@ -182,12 +182,40 @@ interface DirectiveParentNode extends BaseParentNode {
directiveLocation: SourceLocation;
}
+/**
+ * Node representing the if:true and if:false directives
+ */
export interface If extends DirectiveParentNode {
type: 'If';
modifier: string;
condition: Expression;
}
+/**
+ * Node representing the lwc:if directive
+ */
+export interface IfBlock extends DirectiveParentNode {
+ type: 'IfBlock';
+ condition: Expression;
+ else?: ElseifBlock | ElseBlock;
+}
+
+/**
+ * Node representing the lwc:elseif directive
+ */
+export interface ElseifBlock extends DirectiveParentNode {
+ type: 'ElseifBlock';
+ condition: Expression;
+ else?: ElseifBlock | ElseBlock;
+}
+
+/**
+ * Node representing the lwc:else directive
+ */
+export interface ElseBlock extends DirectiveParentNode {
+ type: 'ElseBlock';
+}
+
export interface ForEach extends DirectiveParentNode {
type: 'ForEach';
expression: Expression;
@@ -203,11 +231,28 @@ export interface ForOf extends DirectiveParentNode {
export type ForBlock = ForEach | ForOf;
-export type ParentNode = Root | ForBlock | If | BaseElement;
-
-export type ChildNode = ForBlock | If | BaseElement | Comment | Text;
-
-export type Node = Root | ForBlock | If | BaseElement | Comment | Text;
+export type ParentNode = Root | ForBlock | If | IfBlock | ElseifBlock | ElseBlock | BaseElement;
+
+export type ChildNode =
+ | ForBlock
+ | If
+ | IfBlock
+ | ElseifBlock
+ | ElseBlock
+ | BaseElement
+ | Comment
+ | Text;
+
+export type Node =
+ | Root
+ | ForBlock
+ | If
+ | IfBlock
+ | ElseifBlock
+ | ElseBlock
+ | BaseElement
+ | Comment
+ | Text;
export enum ElementDirectiveName {
Dom = 'lwc:dom',