Skip to content

Commit

Permalink
Merge pull request #387 from bem/yeti-or.notEscapeFalsy
Browse files Browse the repository at this point in the history
Utils: escaping functions should’t render undefined/Null/NaN
  • Loading branch information
miripiruni authored Dec 8, 2016
2 parents f68c0a7 + ae3ecc5 commit fb12745
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 5 deletions.
16 changes: 13 additions & 3 deletions docs/en/6-templates-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ Result of BEMHTML templating:
this.xmlEscape(str)
```

Returns the passed `str` string with the following XML symbols escaped: `&`, `<`, `>`.
Returns the passed `str` string with the following XML symbols escaped: `&`,
`<`, `>`. Normaly, expected that `str` is a `String`. But if `str` is
`undefined`, `Null` or `NaN` an empty string returned. If `str` is of any other
type it will be casted to String before escaping.

Usage example:

Expand Down Expand Up @@ -114,7 +117,11 @@ Result of BEMHTML templating:
this.attrEscape(str)
```

Returns the passed `str` string with the following characters for XML and HTML attributes escaped: `"` and `&`.
Returns the passed `str` string with the following characters for XML and HTML
attributes escaped: `"` and `&`. Normaly, expected that `str` is a `String`.
But if `str` is `undefined`, `Null` or `NaN` type you get empty string.
If `str` is any other type you get native casting from it type to `String`
before escaping.

#### jsAttrEscape

Expand All @@ -126,7 +133,10 @@ Returns the passed `str` string with the following characters for XML and HTML a
this.jsAttrEscape(str)
```

Returns the passed `str` string with the following characters escaped: `'` and `&`.
Returns the passed `str` string with the following characters escaped: `'` and
`&`. Normaly, expected that `str` is a `String`. But if `str` is `undefined`,
`Null` or `NaN` type you get empty string. If `str` is any other type you get
native casting from it type to `String` before escaping.

By default, input data from the [`js`](4-data.md#js) field and data from the [`js`](5-templates-syntax.md#js) mode are escaped using this function.

Expand Down
13 changes: 11 additions & 2 deletions docs/ru/6-templates-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ block('company').attr()(function() {
this.xmlEscape(str)
```

Возвращает переданную строку `str` с заэкранированными символами XML: `&`, `<`, `>`.
Возвращает переданную строку `str` с заэкранированными символами XML: `&`, `<`,
`>`. Ожидается, что `str` это строка. Но если `str` это `undefined`,
`Null` или `NaN`, то функция возвратит пустую строку. Если `str` любого другого
типа, то перед экранированием этот тип будет приведен к строке.

Пример использования:

Expand Down Expand Up @@ -112,7 +115,10 @@ block('button').def()(function() {
this.attrEscape(str)
```

Возвращает переданную строку `str` с заэкранированными символами XML- и HTML-атрибутов: `"` и `&`.
Возвращает переданную строку `str` с заэкранированными символами XML- и
HTML-атрибутов: `"` и `&`. Ожидается, что `str` это строка. Но если `str` это
`undefined`, `Null` или `NaN`, то функция возвратит пустую строку. Если `str`
любого другого типа, то перед экранированием этот тип будет приведен к строке.

#### jsAttrEscape

Expand All @@ -125,6 +131,9 @@ this.jsAttrEscape(str)
```

Возвращает переданную строку `str` с заэкранированными символами: `'` и `&`.
Ожидается, что `str` это строка. Но если `str` это `undefined`, `Null` или
`NaN`, то функция возвратит пустую строку. Если `str` любого другого типа, то
перед экранированием этот тип будет приведен к строке.

По умолчанию входные данные из поля [`js`](4-data.md#js) и данные из режима [`js`](5-templates-syntax.md#js) экранируются этой функцией.

Expand Down
16 changes: 16 additions & 0 deletions lib/bemxjst/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ var singleQuot = '&#39;';
var matchXmlRegExp = /[&<>]/;

exports.xmlEscape = function(string) {
if (typeof string === 'undefined' ||
string === null ||
(typeof string === 'number' && isNaN(string))
)
return '';

var str = '' + string;
var match = matchXmlRegExp.exec(str);

Expand Down Expand Up @@ -48,6 +54,11 @@ exports.xmlEscape = function(string) {
var matchAttrRegExp = /["&]/;

exports.attrEscape = function(string) {
if (typeof string === 'undefined' ||
string === null ||
(typeof string === 'number' && isNaN(string)))
return '';

var str = '' + string;
var match = matchAttrRegExp.exec(str);

Expand Down Expand Up @@ -86,6 +97,11 @@ exports.attrEscape = function(string) {
var matchJsAttrRegExp = /['&]/;

exports.jsAttrEscape = function(string) {
if (typeof string === 'undefined' ||
string === null ||
(typeof string === 'number' && isNaN(string)))
return '';

var str = '' + string;
var match = matchJsAttrRegExp.exec(str);

Expand Down
64 changes: 64 additions & 0 deletions test/bemcontext-attrescape-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var fixtures = require('./fixtures')('bemhtml');
var compile = fixtures.compile;
var test = fixtures.test;

describe('BEMContext this.attrEscape(str)', function() {
Expand All @@ -11,4 +12,67 @@ describe('BEMContext this.attrEscape(str)', function() {
{ block: 'button' },
'<b id=&quot;a&quot; class=&quot;bem&quot;>a&amp;b&amp;c</b>');
});

describe('Type of argument', function() {
var bemhtml;

before(function() {
bemhtml = compile(function() {
block('b').def()(function(n, ctx) {
return n.attrEscape(ctx.val);
});
});
});

it('should return \'\' for undefined', function() {
bemhtml.apply({ block: 'b', val: undefined }).should.equal('');
});

it('should return \'\' for null', function() {
bemhtml.apply({ block: 'b', val: null }).should.equal('');
});

it('should return String for zero', function() {
bemhtml.apply({ block: 'b', val: 0 }).should.equal('0');
});

it('should return String for Number', function() {
bemhtml.apply({ block: 'b', val: 42 }).should.equal('42');
});

it('should return \'\' for NaN', function() {
bemhtml.apply({ block: 'b', val: NaN }).should.equal('');
});

it('should return String for String', function() {
bemhtml.apply({ block: 'b', val: '' }).should.equal('');
});

it('should return String for String', function() {
bemhtml.apply({ block: 'b', val: 'test' }).should.equal('test');
});

it('should return String for Boolean', function() {
bemhtml.apply({ block: 'b', val: false }).should.equal('false');
});

it('should return String for Array', function() {
bemhtml.apply({ block: 'b', val: [] }).should.equal('');
});

it('should return String for Array', function() {
bemhtml.apply({ block: 'b', val: [ 'a', 'b' ] }).should.equal('a,b');
});

it('should return \'\' for Object', function() {
bemhtml.apply({ block: 'b', val: {
toString: function() { return ''; }
} }).should.equal('');
});

it('should return \'\' for Function', function() {
bemhtml.apply({ block: 'b', val: function() {} })
.should.equal('function () {}');
});
});
});
63 changes: 63 additions & 0 deletions test/bemcontext-jsattrescape-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,67 @@ describe('BEMContext this.jsAttrEscape(str)', function() {
.should.equal('<b foo="a">&#39;&amp;&#39;</b><b bar="b">&#39;&amp;' +
'&#39;</b>');
});

describe('Type of argument', function() {
var bemhtml;

before(function() {
bemhtml = compile(function() {
block('b').def()(function(n, ctx) {
return n.jsAttrEscape(ctx.val);
});
});
});

it('should return \'\' for undefined', function() {
bemhtml.apply({ block: 'b', val: undefined }).should.equal('');
});

it('should return \'\' for null', function() {
bemhtml.apply({ block: 'b', val: null }).should.equal('');
});

it('should return String for zero', function() {
bemhtml.apply({ block: 'b', val: 0 }).should.equal('0');
});

it('should return String for Number', function() {
bemhtml.apply({ block: 'b', val: 42 }).should.equal('42');
});

it('should return \'\' for NaN', function() {
bemhtml.apply({ block: 'b', val: NaN }).should.equal('');
});

it('should return String for String', function() {
bemhtml.apply({ block: 'b', val: '' }).should.equal('');
});

it('should return String for String', function() {
bemhtml.apply({ block: 'b', val: 'test' }).should.equal('test');
});

it('should return String for Boolean', function() {
bemhtml.apply({ block: 'b', val: false }).should.equal('false');
});

it('should return String for Array', function() {
bemhtml.apply({ block: 'b', val: [] }).should.equal('');
});

it('should return String for Array', function() {
bemhtml.apply({ block: 'b', val: [ 'a', 'b' ] }).should.equal('a,b');
});

it('should return \'\' for Object', function() {
bemhtml.apply({ block: 'b', val: {
toString: function() { return ''; }
} }).should.equal('');
});

it('should return \'\' for Function', function() {
bemhtml.apply({ block: 'b', val: function() {} })
.should.equal('function () {}');
});
});
});
64 changes: 64 additions & 0 deletions test/bemcontext-xmlescape-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var fixtures = require('./fixtures')('bemhtml');
var compile = fixtures.compile;
var test = fixtures.test;

describe('BEMContext this.xmlEscape()', function() {
Expand All @@ -11,4 +12,67 @@ describe('BEMContext this.xmlEscape()', function() {
{ block: 'button' },
'&lt;b&gt;&amp;&lt;/b&gt;');
});

describe('Type of argument', function() {
var bemhtml;

before(function() {
bemhtml = compile(function() {
block('b').def()(function(n, ctx) {
return n.xmlEscape(ctx.val);
});
});
});

it('should return \'\' for undefined', function() {
bemhtml.apply({ block: 'b', val: undefined }).should.equal('');
});

it('should return \'\' for null', function() {
bemhtml.apply({ block: 'b', val: null }).should.equal('');
});

it('should return String for zero', function() {
bemhtml.apply({ block: 'b', val: 0 }).should.equal('0');
});

it('should return String for Number', function() {
bemhtml.apply({ block: 'b', val: 42 }).should.equal('42');
});

it('should return \'\' for NaN', function() {
bemhtml.apply({ block: 'b', val: NaN }).should.equal('');
});

it('should return String for String', function() {
bemhtml.apply({ block: 'b', val: '' }).should.equal('');
});

it('should return String for String', function() {
bemhtml.apply({ block: 'b', val: 'test' }).should.equal('test');
});

it('should return String for Boolean', function() {
bemhtml.apply({ block: 'b', val: false }).should.equal('false');
});

it('should return String for Array', function() {
bemhtml.apply({ block: 'b', val: [] }).should.equal('');
});

it('should return String for Array', function() {
bemhtml.apply({ block: 'b', val: [ 'a', 'b' ] }).should.equal('a,b');
});

it('should return \'\' for Object', function() {
bemhtml.apply({ block: 'b', val: {
toString: function() { return ''; }
} }).should.equal('');
});

it('should return \'\' for Function', function() {
bemhtml.apply({ block: 'b', val: function() {} })
.should.equal('function () {}');
});
});
});

0 comments on commit fb12745

Please sign in to comment.