Skip to content

Commit 6643007

Browse files
chore(#36): switch statement (@mrmlnc)
2 parents 0eeacc9 + 553b0fa commit 6643007

16 files changed

+247
-4
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ You have full control over the delimiters used for injecting locals, as well as
4343
| **unescapeDelimiters** | `['{{{', '}}}']` | Array containing beginning and ending delimiters for unescaped locals |
4444
| **locals** | `{}` | Object containing any local variables you want to be available inside your expressions |
4545
| **conditionalTags** | `['if', 'elseif', 'else']` | Array containing names for tags used for `if/else if/else` statements |
46+
| **switchTags** | `['switch', 'case', 'default']` | Array containing names for tags used for `switch/case/default` statements |
4647
| **loopTags** | `['each']` | Array containing names for `for` loops |
4748
| **scopeTags** | `['scope']` | Array containing names for scopes |
4849

@@ -155,6 +156,34 @@ else
155156
p Foo is probably just foo in the end.
156157
```
157158

159+
### Switch statement
160+
161+
Switch statements act like streamline conditionals. They are useful for when you want to compare a single variable against a series of constants.
162+
163+
```js
164+
locals: { foo: 'foo' }
165+
```
166+
167+
```html
168+
<switch expression="foo">
169+
<case n="'bar'">
170+
<p>Foo really is bar! Revolutionary!</p>
171+
</case>
172+
<case n="'wow'">
173+
<p>Foo is wow, oh man.</p>
174+
</case>
175+
<default>
176+
<p>Foo is probably just foo in the end.</p>
177+
</default>
178+
</switch>
179+
```
180+
181+
```html
182+
<p>Foo is probably just foo in the end.</p>
183+
```
184+
185+
Anything in the `expression` attribute is evaluated directly as an expressions.
186+
158187
### Loops
159188

160189
You can use the `each` tag to build loops. It works with both arrays and objects. For example:

lib/index.js

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const revertBackupedLocals = require('./backup').revert
1010
const placeholders = require('./placeholders')
1111

1212
let delimitersSettings = []
13-
let conditionals, loops, scopes
13+
let conditionals, switches, loops, scopes
1414

1515
/**
1616
* @description Creates a set of local variables within the loop, and evaluates all nodes within the loop, returning their contents
@@ -57,7 +57,7 @@ function executeScope (scope, locals, node) {
5757

5858
/**
5959
* @author Jeff Escalante Denis (@jescalan),
60-
* Malinochkin (mrmlnc),
60+
* Denis Malinochkin (mrmlnc),
6161
* Michael Ciniawsky (@michael-ciniawsky)
6262
* @description Expressions Plugin for PostHTML
6363
* @license MIT
@@ -84,6 +84,7 @@ module.exports = function postHTMLExpressions (options) {
8484
delimiters: ['{{', '}}'],
8585
unescapeDelimiters: ['{{{', '}}}'],
8686
conditionalTags: ['if', 'elseif', 'else'],
87+
switchTags: ['switch', 'case', 'default'],
8788
loopTags: ['each'],
8889
scopeTags: ['scope']
8990
}, options)
@@ -92,6 +93,7 @@ module.exports = function postHTMLExpressions (options) {
9293
loops = options.loopTags
9394
scopes = options.scopeTags
9495
conditionals = options.conditionalTags
96+
switches = options.switchTags
9597

9698
// make a RegExp's to search for placeholders
9799
let before = escapeRegexpString(options.delimiters[0])
@@ -169,7 +171,6 @@ function walk (opts, nodes) {
169171

170172
// сalculate the first path of condition expression
171173
let expressionIndex = 1
172-
173174
let expression = `if (${node.attrs.condition}) { 0 } `
174175

175176
const branches = [node.content]
@@ -225,11 +226,55 @@ function walk (opts, nodes) {
225226
return m
226227
}
227228

229+
// switch tag
230+
if (node.tag === switches[0]) {
231+
// throw an error if it's missing the "expression" attribute
232+
if (!(node.attrs && node.attrs.expression)) {
233+
throw new Error(`the "${switches[0]}" tag must have a "expression" attribute`)
234+
}
235+
236+
// сalculate the first path of condition expression
237+
let expressionIndex = 0
238+
let expression = `switch(${node.attrs.expression}) {`
239+
240+
const branches = []
241+
242+
for (let i = 0; i < node.content.length; i++) {
243+
const currentNode = node.content[i]
244+
if (typeof currentNode === 'string') {
245+
continue
246+
}
247+
248+
if (currentNode.tag === switches[1]) {
249+
// throw an error if it's missing the "n" attribute
250+
if (!(currentNode.attrs && currentNode.attrs.n)) {
251+
throw new Error(`the "${switches[1]}" tag must have a "n" attribute`)
252+
}
253+
expression += `case ${currentNode.attrs.n}: {${expressionIndex++}}; break; `
254+
} else if (currentNode.tag === switches[2]) {
255+
expression += `default: {${expressionIndex++}}`
256+
} else {
257+
throw new Error(`the "${switches[0]}" tag can contain only "${switches[1]}" tags and one "${switches[2]}" tag`)
258+
}
259+
branches.push(currentNode)
260+
}
261+
262+
expression += '}'
263+
264+
// evaluate the expression, get the winning switch branch
265+
const branch = branches[vm.runInContext(expression, ctx)]
266+
267+
// recursive evaluate of branch
268+
Array.prototype.push.apply(m, walk(opts, branch.content))
269+
270+
return m
271+
}
272+
228273
// parse loops
229274
if (node.tag === loops[0]) {
230275
// handle syntax error
231276
if (!(node.attrs && node.attrs.loop)) {
232-
throw new Error(`the "${conditionals[1]}" tag must have a "loop" attribute`)
277+
throw new Error(`the "${loops[0]}" tag must have a "loop" attribute`)
233278
}
234279

235280
// parse the "loop" param

test/expect/switch.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
<p>Hello, from Germany!</p>

test/expect/switch_customtag.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
<p>Hello, from United States!</p>

test/expect/switch_default.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
<p>Hello, from Earth!</p>

test/expect/switch_nested.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
<p>Hello, from Russia!</p>

test/expect/switch_number.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
<p>3</p>

test/fixtures/switch.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<switch expression="country">
2+
<case n="'russia'">
3+
<p>Hello, from Russia!</p>
4+
</case>
5+
<case n="'germany'">
6+
<p>Hello, from Germany!</p>
7+
</case>
8+
<case n="'us'">
9+
<p>Hello, from United States!</p>
10+
</case>
11+
<default>
12+
<p>Hello, from Earth!</p>
13+
</default>
14+
</switch>

test/fixtures/switch_bad_flow.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<switch expression="country">
2+
<case n="'russia'">
3+
<p>Hello, from Russia!</p>
4+
</case>
5+
<p>What?</p>
6+
<default>
7+
<p>Hello, from Earth!</p>
8+
</default>
9+
</switch>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<s expression="country">
2+
<c n="'russia'">
3+
<p>Hello, from Russia!</p>
4+
</c>
5+
<c n="'germany'">
6+
<p>Hello, from Germany!</p>
7+
</c>
8+
<c n="'us'">
9+
<p>Hello, from United States!</p>
10+
</c>
11+
<d>
12+
<p>Hello, from Earth!</p>
13+
</d>
14+
</s>

0 commit comments

Comments
 (0)