Sync with changes made on master.

This commit is contained in:
Kevin Schaaf
2018-10-31 10:16:54 -07:00
parent d44969a211
commit ed6deea83b
2 changed files with 221 additions and 25 deletions
+62 -20
View File
@@ -9,6 +9,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
-->
<link rel="import" href="class.html">
<link rel="import" href="../polymer.html">
<link rel="import" href="../utils/mixin.html">
<script>
@@ -16,15 +17,43 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
'use strict';
const UndefinedArgumentError = class extends Error {
constructor(message) {
constructor(message, arg) {
super(message);
this.arg = arg;
this.name = this.constructor.name;
// Affordances for ensuring instanceof works after babel ES5 compilation
// TODO(kschaaf): Remove after polymer CLI updates to newer Babel that
// sets the constructor/prototype correctly for subclassed builtins
this.constructor = UndefinedArgumentError;
this.__proto__ = UndefinedArgumentError.prototype;
}
};
/**
* Wraps effect functions to catch `UndefinedArgumentError`s and warn.
*
* @param {Object=} effect Effect metadata object
* @param {Object=} fnName Name of user function, if known
* @return {?Object} Effect metadata object
*/
function wrapEffect(effect, fnName) {
if (effect && effect.fn) {
const fn = effect.fn;
effect.fn = function() {
try {
fn.apply(this, arguments);
} catch (e) {
if (e instanceof UndefinedArgumentError) {
console.warn(`Argument '${e.arg}'${fnName ?` for method '${fnName}'` : ''} was undefined. Ensure it has an undefined check.`);
} else {
throw e;
}
}
};
}
return effect;
}
/**
* Mixin to selectively add back Polymer 1.x's `undefined` rules
* governing when observers & computing functions run based
@@ -38,6 +67,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* 2.x+ by allowing legacy code to work while identifying observers and
* computing functions that need undefined checks to work without
* the mixin in Polymer 2.
*
* @mixinFunction
* @polymer
* @summary Mixin to selectively add back Polymer 1.x's `undefined` rules
* governing when observers & computing functions run.
*/
Polymer.LegacyDataMixin = Polymer.dedupingMixin(superClass => {
@@ -59,12 +93,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
*/
_marshalArgs(args, path, props) {
const vals = super._marshalArgs(args, path, props);
if (this._legacyUndefinedCheck && args.length > 1) {
for (let i=0; i<args.length; i++) {
// Per legacy data rules, single-property observers (whether in `properties`
// and in `observers`) are called regardless of whether their argument is
// undefined or not. Multi-property observers must have all arguments defined
if (this._legacyUndefinedCheck && vals.length > 1) {
for (let i=0; i<vals.length; i++) {
if (vals[i] === undefined) {
// Break out of effect's control flow; will be caught in
// wrapped property effect function below
throw new UndefinedArgumentError(`argument '${args[i].name}' is undefined; ensure it has an undefined check`);
const name = args[i].name;
throw new UndefinedArgumentError(`Argument '${name}' is undefined. Ensure it has an undefined check.`, name);
}
}
}
@@ -81,22 +119,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* @return {void}
* @protected
*/
_addPropertyEffect(property, type, effect) {
if (effect && effect.fn) {
const fn = effect.fn;
effect.fn = function() {
try {
fn.apply(this, arguments);
} catch (e) {
if (e instanceof UndefinedArgumentError) {
console.warn(e.message);
} else {
throw e;
}
}
};
}
return super._addPropertyEffect(property, type, effect);
_addPropertyEffect(property, type, effect) {
return super._addPropertyEffect(property, type,
wrapEffect(effect, effect && effect.info && effect.info.methodName));
}
/**
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
* catch `UndefinedArgumentError`s and warn.
*
* @param {Object} templateInfo Template metadata to add effect to
* @param {string} prop Property that should trigger the effect
* @param {Object=} effect Effect metadata object
* @return {void}
* @protected
*/
static _addTemplatePropertyEffect(templateInfo, prop, effect) {
return super._addTemplatePropertyEffect(templateInfo, prop, wrapEffect(effect));
}
}
@@ -105,6 +144,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
});
// LegacyDataMixin is applied to base class _before_ metaprogramming, to
// ensure override of _addPropertyEffect et.al. are used by metaprogramming
// performed in _finalizeClass
const Class = Polymer.Class;
Polymer.Class = (info, mixin) => Class(info,
superClass => mixin ?