From 1780876b99c8eb9910e4f8c3d1192db392890d43 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 26 Mar 2017 14:00:52 -0400 Subject: [PATCH] prevent infinite loops caused by pathological component bindings (#398) --- .../attributes/addComponentBinding.js | 3 + .../component-binding-infinite-loop/A.html | 12 +++ .../component-binding-infinite-loop/B.html | 20 +++++ .../component-binding-infinite-loop/C.html | 23 +++++ .../_config.js | 90 +++++++++++++++++++ .../component-binding-infinite-loop/main.html | 17 ++++ 6 files changed, 165 insertions(+) create mode 100644 test/generator/samples/component-binding-infinite-loop/A.html create mode 100644 test/generator/samples/component-binding-infinite-loop/B.html create mode 100644 test/generator/samples/component-binding-infinite-loop/C.html create mode 100644 test/generator/samples/component-binding-infinite-loop/_config.js create mode 100644 test/generator/samples/component-binding-infinite-loop/main.html diff --git a/src/generators/dom/visitors/attributes/addComponentBinding.js b/src/generators/dom/visitors/attributes/addComponentBinding.js index baee355619..68c862cb6e 100644 --- a/src/generators/dom/visitors/attributes/addComponentBinding.js +++ b/src/generators/dom/visitors/attributes/addComponentBinding.js @@ -45,6 +45,7 @@ export default function createBinding ( generator, node, attribute, current, loc component._bindings.push( function () { if ( ${local.name}._torndown ) return; ${local.name}.observe( '${attribute.name}', function ( value ) { + if ( ${local.name}_updating ) return; ${local.name}_updating = true; ${setter} ${local.name}_updating = false; @@ -54,7 +55,9 @@ export default function createBinding ( generator, node, attribute, current, loc local.update.addBlock( deindent` if ( !${local.name}_updating && ${dependencies.map( dependency => `'${dependency}' in changed` ).join( '||' )} ) { + ${local.name}_updating = true; ${local.name}._set({ ${attribute.name}: ${snippet} }); + ${local.name}_updating = false; } ` ); } diff --git a/test/generator/samples/component-binding-infinite-loop/A.html b/test/generator/samples/component-binding-infinite-loop/A.html new file mode 100644 index 0000000000..d625b3d6a9 --- /dev/null +++ b/test/generator/samples/component-binding-infinite-loop/A.html @@ -0,0 +1,12 @@ + + + + diff --git a/test/generator/samples/component-binding-infinite-loop/B.html b/test/generator/samples/component-binding-infinite-loop/B.html new file mode 100644 index 0000000000..2b29739886 --- /dev/null +++ b/test/generator/samples/component-binding-infinite-loop/B.html @@ -0,0 +1,20 @@ +{{#each list as item}} +

+ + {{item}} + +

+{{/each}} + + diff --git a/test/generator/samples/component-binding-infinite-loop/C.html b/test/generator/samples/component-binding-infinite-loop/C.html new file mode 100644 index 0000000000..40dcf90844 --- /dev/null +++ b/test/generator/samples/component-binding-infinite-loop/C.html @@ -0,0 +1,23 @@ + + {{yield}} + + + diff --git a/test/generator/samples/component-binding-infinite-loop/_config.js b/test/generator/samples/component-binding-infinite-loop/_config.js new file mode 100644 index 0000000000..6a379af0a4 --- /dev/null +++ b/test/generator/samples/component-binding-infinite-loop/_config.js @@ -0,0 +1,90 @@ +export default { + html: ` +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ `, + + test ( assert, component, target, window ) { + const click = new window.MouseEvent( 'click' ); + const spans = target.querySelectorAll( 'span' ); + + spans[0].dispatchEvent( click ); + + assert.equal( component.get( 'currentIdentifier' ), 1 ); + assert.htmlEqual( target.innerHTML, ` +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ ` ); + + spans[0].dispatchEvent( click ); + + assert.equal( component.get( 'currentIdentifier' ), null ); + assert.htmlEqual( target.innerHTML, ` +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ ` ); + } +}; diff --git a/test/generator/samples/component-binding-infinite-loop/main.html b/test/generator/samples/component-binding-infinite-loop/main.html new file mode 100644 index 0000000000..19d43b4751 --- /dev/null +++ b/test/generator/samples/component-binding-infinite-loop/main.html @@ -0,0 +1,17 @@ + + + + \ No newline at end of file