Skip to content

Commit

Permalink
Add legacy-data-mixin as 1.x->2.x/3.x migration aide. Fixes #5262.
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinpschaaf committed Aug 21, 2018
1 parent c9b539f commit e385e49
Show file tree
Hide file tree
Showing 5 changed files with 427 additions and 81 deletions.
10 changes: 7 additions & 3 deletions lib/legacy/class.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,16 +334,20 @@ function GenerateClassFromInfo(info, Base) {
*
* @param {!PolymerInit} info Object containing Polymer metadata and functions
* to become class methods.
* @template T
* @param {function(T):T} mixin Optional mixin to apply to legacy base class
* @return {function(new:HTMLElement)} Generated class
*/
export const Class = function(info) {
export const Class = function(info, mixin) {
if (!info) {
console.warn(`Polymer's Class function requires \`info\` argument`);
}
let klass = GenerateClassFromInfo(info, info.behaviors ?
const baseWithBehaviors = info.behaviors ?
// note: mixinBehaviors ensures `LegacyElementMixin`.
mixinBehaviors(info.behaviors, HTMLElement) :
LegacyElementMixin(HTMLElement));
LegacyElementMixin(HTMLElement);
const baseWithMixin = mixin ? mixin(baseWithBehaviors) : baseWithBehaviors;
const klass = GenerateClassFromInfo(info, baseWithMixin);
// decorate klass with registration info
klass.is = info.is;
return klass;
Expand Down
112 changes: 112 additions & 0 deletions lib/legacy/legacy-data-mixin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

import { Class } from './class.js';
import { Polymer } from '../../polymer-legacy.js';
import { dedupingMixin } from '../utils/mixin.js';

const UndefinedArgumentError = class extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
// Affordances for ensuring instanceof works after babel ES5 compilation
this.constructor = UndefinedArgumentError;
this.__proto__ = UndefinedArgumentError.prototype;
}
};

/**
* Mixin to selectively add back Polymer 1.x's `undefined` rules
* governing when observers & computing functions run based
* on all arguments being defined (reference https://www.polymer-project.org/1.0/docs/devguide/observers#multi-property-observers).
*
* When loaded, all legacy elements (defined with `Polymer({...})`)
* will have the mixin applied. The mixin only restores legacy data handling
* if `_legacyUndefinedCheck: true` is set on the element's prototype.
*
* This mixin is intended for use to help migration from Polymer 1.x to
* 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.
*/
export const LegacyDataMixin = dedupingMixin(superClass => {

/**
* @polymer
* @mixinClass
* @implements {Polymer_LegacyDataMixin}
*/
class LegacyDataMixinClass extends superClass {
/**
* Overrides `Polyer.PropertyEffects` to add `undefined` argument
* checking to match Polymer 1.x style rules
*
* @param {!Array<!MethodArg>} args Array of argument metadata
* @param {string} path Property/path name that triggered the method effect
* @param {Object} props Bag of current property changes
* @return {Array<*>} Array of argument values
* @private
*/
_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++) {
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`);
}
}
}
return vals;
}

/**
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
* catch `UndefinedArgumentError`s and warn.
*
* @param {string} property Property that should trigger the effect
* @param {string} type Effect type, from this.PROPERTY_EFFECT_TYPES
* @param {Object=} effect Effect metadata object
* @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);
}

}

return LegacyDataMixinClass;

});

Polymer.Class = (info, mixin) => Class(info,
superClass => mixin ?
mixin(LegacyDataMixin(superClass)) :
LegacyDataMixin(superClass)
);

console.info('LegacyDataMixin will be applied to all legacy elements.\n' +
'Set `_legacyUndefinedCheck: true` on element class to enable.');
Loading

0 comments on commit e385e49

Please sign in to comment.