mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #3017 from Polymer/2705-kschaaf-strict-parsing
Use stricter binding parsing for efficiency and correctness. Fixes #2705
This commit is contained in:
commit
8a08c279b6
@ -75,7 +75,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
parseAnnotations: function(template) {
|
||||
var list = [];
|
||||
var content = template._content || template.content;
|
||||
this._parseNodeAnnotations(content, list,
|
||||
this._parseNodeAnnotations(content, list,
|
||||
template.hasAttribute('strip-whitespace'));
|
||||
return list;
|
||||
},
|
||||
@ -89,7 +89,24 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
this._parseElementAnnotations(node, list, stripWhiteSpace);
|
||||
},
|
||||
|
||||
_bindingRegex: /([^{[]*)(\{\{|\[\[)(?!\}\}|\]\])(.+?)(?:\]\]|\}\})/g,
|
||||
_bindingRegex: (function() {
|
||||
var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$-]*' + ')';
|
||||
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
|
||||
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
|
||||
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
|
||||
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
|
||||
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
|
||||
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
|
||||
var ARGUMENT_LIST = '(?:' + '\\(\\s*' +
|
||||
'(?:' + ARGUMENTS + '?' + ')' +
|
||||
'\\)\\s*' + ')';
|
||||
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
|
||||
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
|
||||
var CLOSE_BRACKET = '(?:]]|}})';
|
||||
var NEGATE = '(?:(!)\\s*)?'; // Group 2
|
||||
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
|
||||
return new RegExp(EXPRESSION, "g");
|
||||
})(),
|
||||
|
||||
// TODO(kschaaf): We could modify this to allow an escape mechanism by
|
||||
// looking for the escape sequence in each of the matches and converting
|
||||
@ -98,29 +115,24 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
_parseBindings: function(text) {
|
||||
var re = this._bindingRegex;
|
||||
var parts = [];
|
||||
var m, lastIndex;
|
||||
// Example: "literal1{{binding1}}literal2[[binding2]]final"
|
||||
var lastIndex = 0;
|
||||
var m;
|
||||
// Example: "literal1{{prop}}literal2[[!compute(foo,bar)]]final"
|
||||
// Regex matches:
|
||||
// Iteration 1: Iteration 2:
|
||||
// m[1]: 'literal1' 'literal2'
|
||||
// m[2]: '{{' '[['
|
||||
// m[3]: 'binding1' 'binding2'
|
||||
// 'final' is manually substring'ed from end
|
||||
// Iteration 1: Iteration 2:
|
||||
// m[1]: '{{' '[['
|
||||
// m[2]: '' '!'
|
||||
// m[3]: 'prop' 'compute(foo,bar)'
|
||||
while ((m = re.exec(text)) !== null) {
|
||||
// Add literal part
|
||||
if (m[1]) {
|
||||
parts.push({literal: m[1]});
|
||||
if (m.index > lastIndex) {
|
||||
parts.push({literal: text.slice(lastIndex, m.index)});
|
||||
}
|
||||
// Add binding part
|
||||
// Mode (one-way or two)
|
||||
var mode = m[2][0];
|
||||
var mode = m[1][0];
|
||||
var negate = Boolean(m[2]);
|
||||
var value = m[3].trim();
|
||||
// Negate
|
||||
var negate = false;
|
||||
if (value[0] == '!') {
|
||||
negate = true;
|
||||
value = value.substring(1).trim();
|
||||
}
|
||||
var customEvent, notifyEvent, colon;
|
||||
if (mode == '{' && (colon = value.indexOf('::')) > 0) {
|
||||
notifyEvent = value.substring(colon + 2);
|
||||
@ -242,7 +254,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
// if this node didn't get evacipated, parse it.
|
||||
if (node.parentNode) {
|
||||
var childAnnotation = this._parseNodeAnnotations(node, list,
|
||||
var childAnnotation = this._parseNodeAnnotations(node, list,
|
||||
stripWhiteSpace);
|
||||
if (childAnnotation) {
|
||||
childAnnotation.parent = annote;
|
||||
|
@ -26,9 +26,14 @@
|
||||
no-computed="{{foobared(noInlineComputed)}}"
|
||||
compoundAttr1$="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literal')}}"
|
||||
compoundAttr2$="literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literal')}} literal4"
|
||||
compoundAttr3$="{{computeCompound('world', 'username ', 'Hello {0} ')}}"
|
||||
compoundAttr3$="[yes/no]: {{cpnd1}}, {{computeCompound('world', 'username ', 'Hello {0} ')}}"
|
||||
>
|
||||
Test
|
||||
<!-- Malformed bindings to be ignored -->
|
||||
{{really.long.identifier.in.malformed.binding.should.be.ignored]}
|
||||
{{computeFromLiterals(3, 'really.long.literal.in.malformed.binding.should.be.ignored)]}
|
||||
<!-- Should still parse -->
|
||||
{{computeFromLiterals(3, 'foo', bool)}}
|
||||
</div>
|
||||
<x-prop id="boundProps"
|
||||
prop1="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literal')}}"
|
||||
|
@ -777,11 +777,11 @@ suite('compound binding / string interpolation', function() {
|
||||
assert.equal(el.$.boundChild.getAttribute('compoundAttr2'), 'literal1 literal2 literal3 literal literal4');
|
||||
});
|
||||
|
||||
test('compound property attribute with {} in text', function() {
|
||||
test('compound property attribute with {} and [] in text', function() {
|
||||
var el = document.createElement('x-basic');
|
||||
|
||||
assert.equal(el.$.boundChild.getAttribute('compoundAttr3'), 'Hello {0} username world')
|
||||
})
|
||||
el.cpnd1 = 'cpnd1';
|
||||
assert.equal(el.$.boundChild.getAttribute('compoundAttr3'), '[yes/no]: cpnd1, Hello {0} username world');
|
||||
});
|
||||
|
||||
test('compound adjacent textNode bindings', function() {
|
||||
var el = document.createElement('x-basic');
|
||||
@ -825,6 +825,14 @@ suite('compound binding / string interpolation', function() {
|
||||
assert.equal(el.$.compound2.textContent.trim(), 'literal1 literal2 literal3 literal literal4');
|
||||
});
|
||||
|
||||
test('malformed bindings ignored', function() {
|
||||
var el = document.createElement('x-basic');
|
||||
el.bool = true;
|
||||
assert.isTrue(el.$.boundChild.textContent.indexOf('really.long.identifier.in.malformed.binding.should.be.ignored') >= 0, true);
|
||||
assert.isTrue(el.$.boundChild.textContent.indexOf('really.long.literal.in.malformed.binding.should.be.ignored') >= 0, true);
|
||||
assert.isTrue(el.$.boundChild.textContent.indexOf('3foo') >= 0, true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user