Skip to content

Commit 278b7b0

Browse files
authored
Merge pull request #138 from b-gyula/ignoreMissingLocals
Added `missingLocal` option to define how to handle missing local value
2 parents 90ae2da + 4ce6d0e commit 278b7b0

12 files changed

+77
-14
lines changed

lib/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,15 @@ module.exports = function postHTMLExpressions (options) {
161161
return function (tree) {
162162
const { locals } = scriptDataLocals(tree, options)
163163

164-
return normalizeTree(clearRawTag(walk({ locals: { ...options.locals, ...locals }, strictMode: options.strictMode }, tree)), tree.options)
164+
return normalizeTree(
165+
clearRawTag(
166+
walk(
167+
{
168+
locals: { ...options.locals, ...locals },
169+
strictMode: options.strictMode,
170+
missingLocal: options.missingLocal
171+
}, tree)
172+
), tree.options)
165173
}
166174
}
167175

lib/placeholders.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,20 @@ function placeholders (input, ctx, settings, opts) {
6666
value = ctx[expression]
6767
}
6868

69+
// Not found local
70+
if (value === null || value === undefined) {
71+
if (opts.missingLocal === undefined) {
72+
if (opts.strictMode) {
73+
throw new ReferenceError(`'${expression}' is not defined`)
74+
}
75+
} else if (typeof opts.missingLocal === 'string') {
76+
value = opts.missingLocal.replace('{local}', match)
77+
}
78+
}
6979
// Escape html if necessary
7080
if (settings[i].escape && typeof value === 'string') {
7181
value = escapeHTML(value)
72-
}
73-
74-
// Stringify if value object
75-
if (typeof value === 'object') {
82+
} else if (typeof value === 'object') { // Stringify if value object
7683
value = JSON.stringify(value)
7784
}
7885

readme.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,18 @@ You have full control over the delimiters used for injecting locals, as well as
3737

3838
|Option|Default|Description|
3939
|:----:|:-----:|:----------|
40-
| **delimiters** | `['{{', '}}']` | Array containing beginning and ending delimiters for escaped locals |
41-
| **unescapeDelimiters** | `['{{{', '}}}']` | Array containing beginning and ending delimiters for unescaped locals |
42-
| **locals** | `{}` | Object containing any local variables you want to be available inside your expressions |
40+
| **delimiters** | `['{{', '}}']` | Array containing beginning and ending delimiters for escaped locals os [expressions](#expressions) |
41+
| [**unescapeDelimiters**](#unescaped-locals) | `['{{{', '}}}']` | Array containing beginning and ending delimiters for unescaped locals |
42+
| [**locals**](#locals) | `{}` | Object containing any local variables you want to be available inside your expressions |
4343
| **localsAttr** | `locals` | Attribute name for the tag `script` which contains ***[locals](#locals)***|
4444
| **removeScriptLocals** | `false` | Will remove tag `script` which contains ***[locals](#locals)***|
45-
| **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 |
45+
| [**conditionalTags**](#conditionals) | `['if', 'elseif', 'else']` | Array containing names for tags used for [*`if/else` statements*](#conditionals) |
46+
| [**switchTags**](#switchtags) | `['switch', 'case', 'default']` | Array containing names for tags used for [*`switch/case/default` statements*](#switch-statement) |
4747
| **loopTags** | `['each']` | Array containing names for `for` loops |
4848
| **scopeTags** | `['scope']` | Array containing names for scopes |
49-
| **ignoredTag** | `'raw'` | String containing name of tag inside which parsing is disabled |
50-
| **strictMode** | `true` | Boolean value set to `false` will not throw an exception |
49+
| [**ignoredTag**](#ignored-tag) | `'raw'` | String containing name of tag inside which parsing is disabled |
50+
| **strictMode** | `true` | Boolean value set to `false` will not throw an exception if a value in locals not found or expression could not be evaluated|
51+
| [**missingLocal**](#missing-locals) | `undefined` | string defining the replacement value in case value not found in locals. May contain `{expression}` placeholder|
5152

5253
### Locals
5354

@@ -124,6 +125,23 @@ posthtml(expressions({ locals: { foo: 'bar' } }))
124125
<div>My name: {{name}}</div>
125126
<div>Foo: bar</div>
126127
```
128+
#### Missing locals
129+
What to produce in case of referencing a value not in `locals` can be configured by the `missingLocal` and `strictMode` options.
130+
131+
When `strictMode` is true (default) and leaving the `missingLocal` option `undefined`, then "'foo' is not defined" exception is thrown.
132+
133+
Setting `strictMode` false and leaving the `missingLocal` option `undefined` results the string `undefined` in the output
134+
135+
Setting the option `missingLocal` to a string will produce that string in the output regardless the value of option `strictMode`. `missingLocal` can contain the placeholder `{local}` which will be replaced with the name of the missing local in the output. This solution allows to:
136+
1. Silently ignore missing locals by setting `missingLocal` to `""`
137+
2. Include the name of the missing local in the output to help detect the which value is missing in `locals` like "#Missing value: {local}"
138+
139+
|`missingLocal`|`strictMode`|output|
140+
|:----:|:-----:|:----------|
141+
| `undefined` (default) | `true` (default) | Error is thrown |
142+
| `undefined` (default) | `false` | 'undefined' |
143+
| `''` | `false`/`true` | `''` (not output)
144+
| `{local}` | `false`/`true` | original reference like `{{foo}}`
127145

128146
### Unescaped Locals
129147

test/expect/local_missing.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>undefined<b>undefined</b></p>

test/expect/local_missing_keep.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>{{foo}}</p>

test/expect/local_missing_remove.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p><b></b></p>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>Error: {{foo}} undefined</p>

test/fixtures/local_missing.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>{{foo}}<b>{{foo? "bar": ""}}</b></p>

test/fixtures/local_missing_keep.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>{{foo}}</p>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>{{foo}}</p>

0 commit comments

Comments
 (0)