Repository: sveltejs/svelte (JavaScript)
Date: 2019-02-27 13:20:43+00:00
Task type: Feature

Issue:
{:elseif foo} or {:else if foo} ?
Writing the docs for v3, got to the section on `{:elseif ...}` and realised that I couldn't quite justify why it's that instead of `{:else if ...}`.

Should we change it? If so, now would be the time to do it.

Arguments for changing (sound off in the comments and I'll update the bullet point lists):

* `else if` is JavaScriptier
* Muscle memory
* it... kinda looks nicer, I think?

Arguments against:

* `elseif` is arguably more consistent with other templating languages
* If in doubt, the presumption should be in favour of not changing
* you can double-click `elseif` to highlight the whole word, which @arxpoetica enjoys apparently?

---

```html
<!-- current -->
{#if x > 10}
  <p>{x} is greater than 10</p>
{:elseif 5 > x}
  <p>{x} is less than 5</p>
{:else}
  <p>{x} is between 5 and 10</p>
{/if}
```

```html
<!-- alternative -->
{#if x > 10}
  <p>{x} is greater than 10</p>
{:else if 5 > x}
  <p>{x} is less than 5</p>
{:else}
  <p>{x} is between 5 and 10</p>
{/if}
```




Issue discussion:
In case you have a preference but don't feel like writing an essay about it, I've created a poll: https://www.strawpoll.me/17510302
Perhaps allow for both? PHP for example allows for this

Solution patch:
diff --git a/src/parse/state/mustache.ts b/src/parse/state/mustache.ts
--- a/src/parse/state/mustache.ts
+++ b/src/parse/state/mustache.ts
@@ -86,58 +86,73 @@ export default function mustache(parser: Parser) {
 
 		block.end = parser.index;
 		parser.stack.pop();
-	} else if (parser.eat(':elseif')) {
-		const block = parser.current();
-		if (block.type !== 'IfBlock')
+	} else if (parser.eat(':else')) {
+		if (parser.eat('if')) {
 			parser.error({
-				code: `invalid-elseif-placement`,
-				message: 'Cannot have an {:elseif ...} block outside an {#if ...} block'
+				code: 'invalid-elseif',
+				message: `'elseif' should be 'else if'`
 			});
+		}
 
-		parser.requireWhitespace();
+		parser.allowWhitespace();
 
-		const expression = readExpression(parser);
+		// :else if
+		if (parser.eat('if')) {
+			const block = parser.current();
+			if (block.type !== 'IfBlock')
+				parser.error({
+					code: `invalid-elseif-placement`,
+					message: 'Cannot have an {:else if ...} block outside an {#if ...} block'
+				});
 
-		parser.allowWhitespace();
-		parser.eat('}', true);
+			parser.requireWhitespace();
 
-		block.else = {
-			start: parser.index,
-			end: null,
-			type: 'ElseBlock',
-			children: [
-				{
-					start: parser.index,
-					end: null,
-					type: 'IfBlock',
-					elseif: true,
-					expression,
-					children: [],
-				},
-			],
-		};
+			const expression = readExpression(parser);
 
-		parser.stack.push(block.else.children[0]);
-	} else if (parser.eat(':else')) {
-		const block = parser.current();
-		if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
-			parser.error({
-				code: `invalid-else-placement`,
-				message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block'
-			});
+			parser.allowWhitespace();
+			parser.eat('}', true);
+
+			block.else = {
+				start: parser.index,
+				end: null,
+				type: 'ElseBlock',
+				children: [
+					{
+						start: parser.index,
+						end: null,
+						type: 'IfBlock',
+						elseif: true,
+						expression,
+						children: [],
+					},
+				],
+			};
+
+			parser.stack.push(block.else.children[0]);
 		}
 
-		parser.allowWhitespace();
-		parser.eat('}', true);
+		// :else
+		else {
+			const block = parser.current();
+			if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
+				parser.error({
+					code: `invalid-else-placement`,
+					message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block'
+				});
+			}
+
+			parser.allowWhitespace();
+			parser.eat('}', true);
 
-		block.else = {
-			start: parser.index,
-			end: null,
-			type: 'ElseBlock',
-			children: [],
-		};
+			block.else = {
+				start: parser.index,
+				end: null,
+				type: 'ElseBlock',
+				children: [],
+			};
 
-		parser.stack.push(block.else);
+			parser.stack.push(block.else);
+		}
 	} else if (parser.eat(':then')) {
 		// TODO DRY out this and the next section
 		const pendingBlock = parser.current();


Test patch:
diff --git a/test/parser/samples/if-block-elseif/input.svelte b/test/parser/samples/if-block-elseif/input.svelte
--- a/test/parser/samples/if-block-elseif/input.svelte
+++ b/test/parser/samples/if-block-elseif/input.svelte
@@ -1,5 +1,5 @@
 {#if x > 10}
 	<p>x is greater than 10</p>
-{:elseif x < 5}
+{:else if x < 5}
 	<p>x is less than 5</p>
 {/if}
diff --git a/test/parser/samples/if-block-elseif/output.json b/test/parser/samples/if-block-elseif/output.json
--- a/test/parser/samples/if-block-elseif/output.json
+++ b/test/parser/samples/if-block-elseif/output.json
@@ -1,12 +1,12 @@
 {
 	"html": {
 		"start": 0,
-		"end": 88,
+		"end": 89,
 		"type": "Fragment",
 		"children": [
 			{
 				"start": 0,
-				"end": 88,
+				"end": 89,
 				"type": "IfBlock",
 				"expression": {
 					"type": "BinaryExpression",
@@ -45,45 +45,45 @@
 					}
 				],
 				"else": {
-					"start": 57,
-					"end": 83,
+					"start": 58,
+					"end": 84,
 					"type": "ElseBlock",
 					"children": [
 						{
-							"start": 57,
-							"end": 88,
+							"start": 58,
+							"end": 89,
 							"type": "IfBlock",
 							"elseif": true,
 							"expression": {
 								"type": "BinaryExpression",
-								"start": 51,
-								"end": 56,
+								"start": 52,
+								"end": 57,
 								"left": {
 									"type": "Identifier",
-									"start": 51,
-									"end": 52,
+									"start": 52,
+									"end": 53,
 									"name": "x"
 								},
 								"operator": "<",
 								"right": {
 									"type": "Literal",
-									"start": 55,
-									"end": 56,
+									"start": 56,
+									"end": 57,
 									"value": 5,
 									"raw": "5"
 								}
 							},
 							"children": [
 								{
-									"start": 59,
-									"end": 82,
+									"start": 60,
+									"end": 83,
 									"type": "Element",
 									"name": "p",
 									"attributes": [],
 									"children": [
 										{
-											"start": 62,
-											"end": 78,
+											"start": 63,
+											"end": 79,
 											"type": "Text",
 											"data": "x is less than 5"
 										}
@@ -95,8 +95,5 @@
 				}
 			}
 		]
-	},
-	"css": null,
-	"instance": null,
-	"module": null
+	}
 }
\ No newline at end of file
diff --git a/test/runtime/samples/dynamic-component-slot/main.svelte b/test/runtime/samples/dynamic-component-slot/main.svelte
--- a/test/runtime/samples/dynamic-component-slot/main.svelte
+++ b/test/runtime/samples/dynamic-component-slot/main.svelte
@@ -17,7 +17,7 @@
 
 	{#if foo}
 		<p>foo</p>
-	{:elseif bar}
+	{:else if bar}
 		<p>bar</p>
 	{:else}
 		<p>neither foo nor bar</p>
diff --git a/test/runtime/samples/if-block-elseif-no-else/main.svelte b/test/runtime/samples/if-block-elseif-no-else/main.svelte
--- a/test/runtime/samples/if-block-elseif-no-else/main.svelte
+++ b/test/runtime/samples/if-block-elseif-no-else/main.svelte
@@ -1,5 +1,5 @@
 {#if x > 10}
 	<p>x is greater than 10</p>
-{:elseif x < 5}
+{:else if x < 5}
 	<p>x is less than 5</p>
 {/if}
diff --git a/test/runtime/samples/if-block-elseif-text/main.svelte b/test/runtime/samples/if-block-elseif-text/main.svelte
--- a/test/runtime/samples/if-block-elseif-text/main.svelte
+++ b/test/runtime/samples/if-block-elseif-text/main.svelte
@@ -1 +1 @@
-before-{#if x > 10}if{:elseif x < 5}elseif{:else}else{/if}-after
+before-{#if x > 10}if{:else if x < 5}elseif{:else}else{/if}-after
diff --git a/test/runtime/samples/if-block-elseif/main.svelte b/test/runtime/samples/if-block-elseif/main.svelte
--- a/test/runtime/samples/if-block-elseif/main.svelte
+++ b/test/runtime/samples/if-block-elseif/main.svelte
@@ -1,6 +1,6 @@
 {#if x > 10}
 	<p>x is greater than 10</p>
-{:elseif x < 5}
+{:else if x < 5}
 	<p>x is less than 5</p>
 {:else}
 	<p>x is between 5 and 10</p>
diff --git a/test/runtime/samples/if-block-outro-nested-else/main.svelte b/test/runtime/samples/if-block-outro-nested-else/main.svelte
--- a/test/runtime/samples/if-block-outro-nested-else/main.svelte
+++ b/test/runtime/samples/if-block-outro-nested-else/main.svelte
@@ -7,7 +7,7 @@
 {#if foo}
 	{#if false}
 		<Component/>
-	{:elseif false}
+	{:else if false}
 		<Component/>
 	{/if}
 {/if}
diff --git a/test/runtime/samples/transition-js-if-elseif-block-outro/main.svelte b/test/runtime/samples/transition-js-if-elseif-block-outro/main.svelte
--- a/test/runtime/samples/transition-js-if-elseif-block-outro/main.svelte
+++ b/test/runtime/samples/transition-js-if-elseif-block-outro/main.svelte
@@ -17,6 +17,6 @@
 
 {#if x}
 	<div bind:this={yes} out:foo>yes</div>
-{:elseif y}
+{:else if y}
 	<div bind:this={no} out:foo>no</div>
 {/if}
\ No newline at end of file