Skip to content

Commit cb86634

Browse files
authored
Merge pull request #5474 from Polymer/legacy-warnings-3.x
Legacy warnings 3.x
2 parents 5501554 + 21e83e9 commit cb86634

File tree

2 files changed

+145
-6
lines changed

2 files changed

+145
-6
lines changed

lib/mixins/element-mixin.js

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ export const ElementMixin = dedupingMixin(base => {
195195
* disables the effect, the setter would fail unexpectedly.
196196
* Based on feedback, we may want to try to make effects more malleable
197197
* and/or provide an advanced api for manipulating them.
198-
* Also consider adding warnings when an effect cannot be changed.
199198
*
200199
* @param {!PolymerElement} proto Element class prototype to add accessors
201200
* and effects to
@@ -217,17 +216,27 @@ export const ElementMixin = dedupingMixin(base => {
217216
// setup where multiple triggers for setting a property)
218217
// While we do have `hasComputedEffect` this is set on the property's
219218
// dependencies rather than itself.
220-
if (info.computed && !proto._hasReadOnlyEffect(name)) {
221-
proto._createComputedProperty(name, info.computed, allProps);
219+
if (info.computed) {
220+
if (proto._hasReadOnlyEffect(name)) {
221+
console.warn(`Cannot redefine computed property '${name}'.`);
222+
} else {
223+
proto._createComputedProperty(name, info.computed, allProps);
224+
}
222225
}
223226
if (info.readOnly && !proto._hasReadOnlyEffect(name)) {
224227
proto._createReadOnlyProperty(name, !info.computed);
228+
} else if (info.readOnly === false && proto._hasReadOnlyEffect(name)) {
229+
console.warn(`Cannot make readOnly property '${name}' non-readOnly.`);
225230
}
226231
if (info.reflectToAttribute && !proto._hasReflectEffect(name)) {
227232
proto._createReflectedProperty(name);
233+
} else if (info.reflectToAttribute === false && proto._hasReflectEffect(name)) {
234+
console.warn(`Cannot make reflected property '${name}' non-reflected.`);
228235
}
229236
if (info.notify && !proto._hasNotifyEffect(name)) {
230237
proto._createNotifyingProperty(name);
238+
} else if (info.notify === false && proto._hasNotifyEffect(name)) {
239+
console.warn(`Cannot make notify property '${name}' non-notify.`);
231240
}
232241
// always add observer
233242
if (info.observer) {
@@ -718,7 +727,7 @@ export const ElementMixin = dedupingMixin(base => {
718727
}
719728

720729
/**
721-
* Overrides `PropertyAccessors` to add map of dynamic functions on
730+
* Overrides `PropertyEffects` to add map of dynamic functions on
722731
* template info, for consumption by `PropertyEffects` template binding
723732
* code. This map determines which method templates should have accessors
724733
* created for them.
@@ -734,6 +743,32 @@ export const ElementMixin = dedupingMixin(base => {
734743
return super._parseTemplateContent(template, templateInfo, nodeInfo);
735744
}
736745

746+
/**
747+
* Overrides `PropertyEffects` to warn on use of undeclared properties in
748+
* template.
749+
*
750+
* @param {Object} templateInfo Template metadata to add effect to
751+
* @param {string} prop Property that should trigger the effect
752+
* @param {Object=} effect Effect metadata object
753+
* @return {void}
754+
* @protected
755+
*/
756+
static _addTemplatePropertyEffect(templateInfo, prop, effect) {
757+
// Warn if properties are used in template without being declared.
758+
// Properties must be listed in `properties` to be included in
759+
// `observedAttributes` since CE V1 reads that at registration time, and
760+
// since we want to keep template parsing lazy, we can't automatically
761+
// add undeclared properties used in templates to `observedAttributes`.
762+
// The warning is only enabled in `legacyOptimizations` mode, since
763+
// we don't want to spam existing users who might have adopted the
764+
// shorthand when attribute deserialization is not important.
765+
if (legacyOptimizations && !(prop in this._properties)) {
766+
console.warn(`Property '${prop}' used in template but not declared in 'properties'; ` +
767+
`attribute will not be observed.`);
768+
}
769+
return super._addTemplatePropertyEffect(templateInfo, prop, effect);
770+
}
771+
737772
}
738773

739774
return PolymerElement;

test/unit/property-effects.html

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
<script type="module">
2727
import './property-effects-elements.js';
28-
import { Polymer } from '../../lib/legacy/polymer-fn.js';
29-
import { setSanitizeDOMValue, sanitizeDOMValue } from '../../lib/utils/settings.js';
28+
import { Polymer, html } from '../../polymer-legacy.js';
29+
import { setSanitizeDOMValue, sanitizeDOMValue, setLegacyOptimizations } from '../../lib/utils/settings.js';
3030
import { PropertyEffects } from '../../lib/mixins/property-effects.js';
3131

3232
suite('single-element binding effects', function() {
@@ -1872,6 +1872,110 @@
18721872
document.body.removeChild(el);
18731873
});
18741874

1875+
});
1876+
1877+
suite('warn on legacy differences', () => {
1878+
1879+
setup(function() {
1880+
sinon.spy(console, 'warn');
1881+
});
1882+
1883+
teardown(function() {
1884+
setLegacyOptimizations(false);
1885+
console.warn.restore();
1886+
});
1887+
1888+
test('warn if non-declared property used in binding', () => {
1889+
setLegacyOptimizations(true);
1890+
Polymer({
1891+
is: 'x-warn-undeclared-binding',
1892+
_template: html`
1893+
<div attr$="[[undeclaredToAttr]]"
1894+
prop="[[undeclaredToProp]]">
1895+
[[undeclaredToText]]</div>`
1896+
});
1897+
const el = document.createElement('x-warn-undeclared-binding');
1898+
document.body.appendChild(el);
1899+
document.body.removeChild(el);
1900+
assert.equal(console.warn.callCount, 3);
1901+
});
1902+
1903+
test('warn when re-declaring a computed property', () => {
1904+
Polymer({
1905+
is: 'x-warn-redeclared-computed',
1906+
behaviors: [{
1907+
properties: {
1908+
a: { computed: 'compute(x)' }
1909+
}
1910+
}, {
1911+
properties: {
1912+
a: { computed: 'compute(y)' }
1913+
}
1914+
}]
1915+
});
1916+
const el = document.createElement('x-warn-redeclared-computed');
1917+
document.body.appendChild(el);
1918+
document.body.removeChild(el);
1919+
assert.equal(console.warn.callCount, 1);
1920+
});
1921+
1922+
test('warn when disabling readOnly on a readOnly property', () => {
1923+
Polymer({
1924+
is: 'x-warn-disable-readonly',
1925+
behaviors: [{
1926+
properties: {
1927+
a: { readOnly: true }
1928+
}
1929+
}, {
1930+
properties: {
1931+
a: { readOnly: false }
1932+
}
1933+
}]
1934+
});
1935+
const el = document.createElement('x-warn-disable-readonly');
1936+
document.body.appendChild(el);
1937+
document.body.removeChild(el);
1938+
assert.equal(console.warn.callCount, 1);
1939+
});
1940+
1941+
test('warn when disabling reflect on a reflect property', () => {
1942+
Polymer({
1943+
is: 'x-warn-disable-reflect',
1944+
behaviors: [{
1945+
properties: {
1946+
a: { reflectToAttribute: true }
1947+
}
1948+
}, {
1949+
properties: {
1950+
a: { reflectToAttribute: false }
1951+
}
1952+
}]
1953+
});
1954+
const el = document.createElement('x-warn-disable-reflect');
1955+
document.body.appendChild(el);
1956+
document.body.removeChild(el);
1957+
assert.equal(console.warn.callCount, 1);
1958+
});
1959+
1960+
test('warn when disabling notify on a notify property', () => {
1961+
Polymer({
1962+
is: 'x-warn-disable-notify',
1963+
behaviors: [{
1964+
properties: {
1965+
a: { notify: true }
1966+
}
1967+
}, {
1968+
properties: {
1969+
a: { notify: false }
1970+
}
1971+
}]
1972+
});
1973+
const el = document.createElement('x-warn-disable-notify');
1974+
document.body.appendChild(el);
1975+
document.body.removeChild(el);
1976+
assert.equal(console.warn.callCount, 1);
1977+
});
1978+
18751979
});
18761980
</script>
18771981

0 commit comments

Comments
 (0)