From 997240af7531f4bce540e9beb9af81a02a649a41 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 24 Jun 2016 19:46:34 -0700 Subject: [PATCH 1/5] Fixes #3739: correctly shim `:host(.element-name)` as `element-name.element-name`. Also converts `:host(not-element-name)` to a non-matching selector. --- src/lib/style-transformer.html | 32 +++++++++++++++++++++----- test/unit/styling-scoped-elements.html | 4 ++++ test/unit/styling-scoped.html | 8 +++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/lib/style-transformer.html b/src/lib/style-transformer.html index 74adf086f4..aa5a557222 100644 --- a/src/lib/style-transformer.html +++ b/src/lib/style-transformer.html @@ -206,12 +206,7 @@ if (selector.indexOf(HOST_CONTEXT) >=0) { hostContext = true; } else if (selector.indexOf(HOST) >=0) { - // :host(...) -> scopeName... - selector = selector.replace(HOST_PAREN, function(m, host, paren) { - return (m.indexOf(hostScope) === -1 ? hostScope : '') + paren; - }); - // now normal :host - selector = selector.replace(HOST, hostScope); + selector = this._transformHostSelector(selector, hostScope); // replace other selectors with scoping class } else if (jumpIndex !== 0) { selector = scope ? this._transformSimpleSelector(selector, scope) : @@ -238,6 +233,30 @@ return p$.join(PSEUDO_PREFIX); }, + // :host(...) -> scopeName... + _transformHostSelector: function(selector, hostScope) { + var m = HOST_PAREN.exec(selector); + HOST_PAREN.lastIndex = 0; + var paren = m && m[2].trim(); + if (paren) { + var selectorKind = /[[.:#*]/; + if (!paren[0].match(selectorKind)) { + var typeSelector = paren.split(selectorKind)[0]; + if (typeSelector === hostScope) { + hostScope = ''; + } else { + return SELECTOR_NO_MATCH; + } + } + return selector.replace(HOST_PAREN, function(m, host, paren) { + return hostScope + paren; + }); + } else { + // now normal :host + return selector.replace(HOST, hostScope); + } + }, + documentRule: function(rule) { // reset selector in case this is redone. rule.selector = rule.parsedSelector; @@ -283,6 +302,7 @@ var PSEUDO_PREFIX = ':'; var CLASS = 'class'; var CONTENT_START = new RegExp('^(' + CONTENT + ')'); + var SELECTOR_NO_MATCH = 'should_not_match'; // exports return api; diff --git a/test/unit/styling-scoped-elements.html b/test/unit/styling-scoped-elements.html index 0b291139a2..dd6c279f5c 100644 --- a/test/unit/styling-scoped-elements.html +++ b/test/unit/styling-scoped-elements.html @@ -554,6 +554,10 @@ display: block; border: 4px solid orange; } + + :host(.x-shared1) { + padding: 8px; + }; diff --git a/test/unit/styling-scoped.html b/test/unit/styling-scoped.html index 298aba5a95..32264cd494 100644 --- a/test/unit/styling-scoped.html +++ b/test/unit/styling-scoped.html @@ -410,6 +410,14 @@ assertComputed(s2, '4px'); }); + test(':host with superset of element tag selector does not leak', function() { + var t = document.createElement('div'); + t.textContent = 'host leak test'; + t.classList.add('x-shared1'); + document.body.appendChild(t); + assertComputed(t, '0px', 'padding'); + }); + }); From c3355fd1e5d3ac4133baa4f6a3e4eddf49047d01 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 27 Jun 2016 18:03:35 -0700 Subject: [PATCH 2/5] simplify :host fixup --- src/lib/style-transformer.html | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/lib/style-transformer.html b/src/lib/style-transformer.html index aa5a557222..fc493f9521 100644 --- a/src/lib/style-transformer.html +++ b/src/lib/style-transformer.html @@ -235,26 +235,21 @@ // :host(...) -> scopeName... _transformHostSelector: function(selector, hostScope) { - var m = HOST_PAREN.exec(selector); - HOST_PAREN.lastIndex = 0; - var paren = m && m[2].trim(); - if (paren) { - var selectorKind = /[[.:#*]/; - if (!paren[0].match(selectorKind)) { - var typeSelector = paren.split(selectorKind)[0]; - if (typeSelector === hostScope) { - hostScope = ''; - } else { - return SELECTOR_NO_MATCH; - } + var m = selector.match(HOST_PAREN); + var paren = m && m[2].trim() || ''; + if (paren && !paren[0].match(SIMPLE_SELECTOR_PREFIX)) { + // paren starts with a type selector + var typeSelector = paren.split(SIMPLE_SELECTOR_PREFIX)[0]; + // if the type selector is our hostScope then avoid pre-pending it + if (typeSelector === hostScope) { + return paren; + // otherwise, this selector should not match in this scope so + // output a bogus selector. + } else { + return SELECTOR_NO_MATCH; } - return selector.replace(HOST_PAREN, function(m, host, paren) { - return hostScope + paren; - }); - } else { - // now normal :host - return selector.replace(HOST, hostScope); } + return hostScope + paren; }, documentRule: function(rule) { @@ -286,12 +281,13 @@ ':not(.' + SCOPE_NAME + ')'; var COMPLEX_SELECTOR_SEP = ','; var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g; + var SIMPLE_SELECTOR_PREFIX = /[[.:#*]/; var HOST = ':host'; var ROOT = ':root'; // NOTE: this supports 1 nested () pair for things like // :host(:not([selected]), more general support requires // parsing which seems like overkill - var HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g; + var HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/; var HOST_CONTEXT = ':host-context'; var HOST_CONTEXT_PAREN = /(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/; var CONTENT = '::content'; From ec111f10acac5f78b2ba81a49c023f911fb174fa Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 27 Jun 2016 18:29:27 -0700 Subject: [PATCH 3/5] fix test in IE/FF. --- test/unit/styling-scoped-elements.html | 2 +- test/unit/styling-scoped.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/styling-scoped-elements.html b/test/unit/styling-scoped-elements.html index dd6c279f5c..e69da7bf59 100644 --- a/test/unit/styling-scoped-elements.html +++ b/test/unit/styling-scoped-elements.html @@ -556,7 +556,7 @@ } :host(.x-shared1) { - padding: 8px; + top: 10px; }; diff --git a/test/unit/styling-scoped.html b/test/unit/styling-scoped.html index 32264cd494..d502d5905a 100644 --- a/test/unit/styling-scoped.html +++ b/test/unit/styling-scoped.html @@ -415,7 +415,7 @@ t.textContent = 'host leak test'; t.classList.add('x-shared1'); document.body.appendChild(t); - assertComputed(t, '0px', 'padding'); + assertComputed(t, 'auto', 'top'); }); }); From 4e08fa1b7e02d5c79cc0118bb780ee70d80ce725 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 27 Jun 2016 18:47:49 -0700 Subject: [PATCH 4/5] Add test for not matching `x-foox-bar` given `:host(x-bar)` used inside `x-foo` --- test/unit/styling-scoped.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/unit/styling-scoped.html b/test/unit/styling-scoped.html index d502d5905a..d7547740fe 100644 --- a/test/unit/styling-scoped.html +++ b/test/unit/styling-scoped.html @@ -418,6 +418,17 @@ assertComputed(t, 'auto', 'top'); }); + test(':host(...) with non-matching type selector does not leak', function() { + var t = document.createElement('x-shared1x-shared2'); + t.textContent = ':host(non-matching-type-selector)'; + document.body.appendChild(t); + assertComputed(t, '0px'); + var t = document.createElement('x-shared2x-shared1'); + t.textContent = ':host(non-matching-type-selector)'; + document.body.appendChild(t); + assertComputed(t, '0px'); + }); + }); From 4817d6194a3b10756a80be7823bc17202a986a5b Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 27 Jun 2016 18:53:30 -0700 Subject: [PATCH 5/5] fix linting --- test/unit/styling-scoped.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/styling-scoped.html b/test/unit/styling-scoped.html index d7547740fe..d37f11319a 100644 --- a/test/unit/styling-scoped.html +++ b/test/unit/styling-scoped.html @@ -423,7 +423,7 @@ t.textContent = ':host(non-matching-type-selector)'; document.body.appendChild(t); assertComputed(t, '0px'); - var t = document.createElement('x-shared2x-shared1'); + t = document.createElement('x-shared2x-shared1'); t.textContent = ':host(non-matching-type-selector)'; document.body.appendChild(t); assertComputed(t, '0px');