Skip to content

Commit

Permalink
Merge pull request #799 from Polymer/mixin-prototype
Browse files Browse the repository at this point in the history
Allow mixin classes to have members added via .prototype calls.
  • Loading branch information
aomarks authored Dec 3, 2018
2 parents 1e32fc3 + fe0a724 commit ce5ca6c
Show file tree
Hide file tree
Showing 22 changed files with 296 additions and 36 deletions.
4 changes: 3 additions & 1 deletion packages/analyzer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

<!-- ## Unreleased -->
## Unreleased
* Support annotating mixin class properties and methods using
`MixinClass.prototype.foo` syntax.
<!-- Add new, unreleased changes here. -->

## [3.1.3] - 2018-10-15
Expand Down
18 changes: 9 additions & 9 deletions packages/analyzer/src/javascript/class-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,16 @@ export class ClassScanner implements JavaScriptScanner {
document: JavaScriptDocument,
visit: (visitor: Visitor) => Promise<void>) {
const classFinder = new ClassFinder(document);
const mixinFinder = new MixinVisitor(document);
const elementDefinitionFinder =
new CustomElementsDefineCallFinder(document);
const prototypeMemberFinder = new PrototypeMemberFinder(document);
await visit(prototypeMemberFinder);
const mixinFinder = new MixinVisitor(document, prototypeMemberFinder);
// Find all classes and all calls to customElements.define()
await Promise.all([
visit(classFinder),
visit(elementDefinitionFinder),
visit(mixinFinder),
visit(prototypeMemberFinder),
]);
const mixins = mixinFinder.mixins;

Expand Down Expand Up @@ -424,7 +424,7 @@ interface CustomElementDefinition {
definition?: ElementDefineCall;
}

class PrototypeMemberFinder implements Visitor {
export class PrototypeMemberFinder implements Visitor {
readonly members = new MapWithDefault<string, {
methods: Map<string, ScannedMethod>,
properties: Map<string, ScannedProperty>
Expand Down Expand Up @@ -505,16 +505,16 @@ class PrototypeMemberFinder implements Visitor {
}

if (jsdoc.hasTag(jsdocAnn, 'function')) {
const prop =
const method =
this._createMethodFromExpression(node.property.name, node, jsdocAnn);
if (prop) {
this._addMethodToClass(cls, prop);
if (method) {
this._addMethodToClass(cls, method);
}
} else {
const method = this._createPropertyFromExpression(
const prop = this._createPropertyFromExpression(
node.property.name, node, jsdocAnn);
if (method) {
this._addPropertyToClass(cls, method);
if (prop) {
this._addPropertyToClass(cls, prop);
}
}
}
Expand Down
24 changes: 21 additions & 3 deletions packages/analyzer/src/polymer/polymer2-mixin-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {NodePath} from '@babel/traverse';
import * as babel from '@babel/types';

import {getIdentifierName, getNamespacedIdentifier} from '../javascript/ast-value';
import {extractPropertiesFromClass} from '../javascript/class-scanner';
import {extractPropertiesFromClass, PrototypeMemberFinder} from '../javascript/class-scanner';
import {Visitor} from '../javascript/estree-visitor';
import * as esutil from '../javascript/esutil';
import {getMethods, getOrInferPrivacy, getStaticMethods} from '../javascript/esutil';
Expand All @@ -34,10 +34,14 @@ export class MixinVisitor implements Visitor {
private _currentMixin: ScannedPolymerElementMixin|null = null;
private _currentMixinNode: babel.Node|null = null;
private _currentMixinFunction: babel.Function|null = null;
private _prototypeMemberFinder: PrototypeMemberFinder;
readonly warnings: Warning[] = [];

constructor(document: JavaScriptDocument) {
constructor(
document: JavaScriptDocument,
prototypeMemberFinder: PrototypeMemberFinder) {
this._document = document;
this._prototypeMemberFinder = prototypeMemberFinder;
}

enterAssignmentExpression(
Expand Down Expand Up @@ -159,7 +163,21 @@ export class MixinVisitor implements Visitor {
mixin.events = esutil.getEventComments(node);
// mixin.sourceRange = this._document.sourceRangeForNode(node);

return mixin;
// Also add members that were described like:
// /** @type {string} */
// MixinClass.prototype.foo;
const name = getIdentifierName(node.id);
if (name !== undefined) {
const prototypeMembers = this._prototypeMemberFinder.members.get(name);
if (prototypeMembers !== undefined) {
for (const [, property] of prototypeMembers.properties) {
mixin.addProperty(property);
}
for (const [, method] of prototypeMembers.methods) {
mixin.addMethod(method);
}
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/gen-typescript-declarations/scripts/fixtures.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ https://github.com/PolymerElements/paper-button.git v2.0.0 paper-button-2
https://github.com/PolymerElements/paper-button.git f644abdfc660f58b6535134ae9a0c16fa7ccaf16 paper-button-3
https://github.com/PolymerElements/paper-menu-button.git v2.0.0 paper-menu-button-2
https://github.com/PolymerElements/paper-menu-button.git ab4885daa67d09a929c8209972e20fbf56014543 paper-menu-button-3
https://github.com/Polymer/polymer.git 50ba80b864d4843d4e59cfdddeab6efdf280a2ec polymer-2
https://github.com/Polymer/polymer.git 646355bef43f4559006675452e4248560a614737 polymer-2
https://github.com/Polymer/polymer.git 7791ee9e8655b6a55ec6e65419d21e9e7eb0a581 polymer-3
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,5 @@ declare namespace Polymer {
*
* @returns Generated class
*/
function Class(info: PolymerInit): {new(): HTMLElement};
function Class<T>(info: PolymerInit, mixin: (p0: T) => T): {new(): HTMLElement};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* DO NOT EDIT
*
* This file was automatically generated by
* https://github.com/Polymer/tools/tree/master/packages/gen-typescript-declarations
*
* To modify these typings, edit the source file(s):
* lib/legacy/legacy-data-mixin.html
*/


// tslint:disable:variable-name Describing an API that's defined elsewhere.
// tslint:disable:no-any describes the API as best we are able today

/// <reference path="class.d.ts" />
/// <reference path="../../polymer.d.ts" />
/// <reference path="../utils/mixin.d.ts" />
/// <reference path="../utils/templatize.d.ts" />

declare class UndefinedArgumentError extends Error {
constructor(message: any, arg: any);
}

declare namespace Polymer {


/**
* 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.
*/
function LegacyDataMixin<T extends new (...args: any[]) => {}>(base: T): T & LegacyDataMixinConstructor;

interface LegacyDataMixinConstructor {
new(...args: any[]): LegacyDataMixin;

/**
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
* catch `UndefinedArgumentError`s and warn.
*
* @param templateInfo Template metadata to add effect to
* @param prop Property that should trigger the effect
* @param effect Effect metadata object
*/
_addTemplatePropertyEffect(templateInfo: object|null, prop: string, effect?: object|null): void;
}

interface LegacyDataMixin {
readonly _legacyUndefinedCheck: any;

/**
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
* catch `UndefinedArgumentError`s and warn.
*
* @param property Property that should trigger the effect
* @param type Effect type, from this.PROPERTY_EFFECT_TYPES
* @param effect Effect metadata object
*/
_addPropertyEffect(property: string, type: string, effect?: object|null): void;
}
}

declare class LegacyDataMixin extends superClass {

/**
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
* catch `UndefinedArgumentError`s and warn.
*
* @param templateInfo Template metadata to add effect to
* @param prop Property that should trigger the effect
* @param effect Effect metadata object
*/
static _addTemplatePropertyEffect(templateInfo: object|null, prop: string, effect?: object|null): void;

/**
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
* catch `UndefinedArgumentError`s and warn.
*
* @param property Property that should trigger the effect
* @param type Effect type, from this.PROPERTY_EFFECT_TYPES
* @param effect Effect metadata object
*/
_addPropertyEffect(property: string, type: string, effect?: object|null): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ declare namespace Polymer {
}

interface LegacyElementMixin extends Polymer.ElementMixin, Polymer.PropertyEffects, Polymer.TemplateStamp, Polymer.PropertyAccessors, Polymer.PropertiesChanged, Polymer.PropertiesMixin, Polymer.GestureEventListeners {
isAttached: boolean;
_debouncers: {[key: string]: Function|null};

/**
* Return the element whose local dom within which this element
* is contained. This is a shorthand for
* `this.getRootNode().host`.
*/
readonly domHost: any;
isAttached: boolean;
_debouncers: {[key: string]: Function|null};
is: string;

/**
* Overrides the default `Polymer.PropertyEffects` implementation to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ declare namespace Polymer {
* find the template.
*/
_finalizeClass(): void;
_prepareTemplate(): void;

/**
* Creates observers for the given `observers` array.
Expand Down Expand Up @@ -227,11 +228,4 @@ declare namespace Polymer {
*/
resolveUrl(url: string, base?: string): string;
}

/**
* Provides basic tracking of element definitions (registrations) and
* instance counts.
*/
namespace telemetry {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// tslint:disable:no-any describes the API as best we are able today

/// <reference path="../utils/boot.d.ts" />
/// <reference path="../utils/telemetry.d.ts" />
/// <reference path="../utils/mixin.d.ts" />
/// <reference path="properties-changed.d.ts" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
declare namespace Polymer {

class Debouncer {
constructor();

/**
* Creates a debouncer if no debouncer is passed as a parameter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,11 @@ declare namespace Polymer {
* Sets `passiveTouchGestures` globally for all elements using Polymer Gestures.
*/
function setPassiveTouchGestures(usePassive: boolean): void;


/**
* Sets `legacyOptimizations` globally for all elements. Enables
* optimizations when only legacy Polymer() style elements are used.
*/
function setLegacyOptimizations(useLegacyOptimizations: boolean): void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* DO NOT EDIT
*
* This file was automatically generated by
* https://github.com/Polymer/tools/tree/master/packages/gen-typescript-declarations
*
* To modify these typings, edit the source file(s):
* lib/utils/telemetry.html
*/


// tslint:disable:variable-name Describing an API that's defined elsewhere.

/// <reference path="boot.d.ts" />

declare namespace Polymer {

/**
* Provides basic tracking of element definitions (registrations) and
* instance counts.
*/
namespace telemetry {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ interface LegacyElementMixin extends ElementMixin, PropertyEffects, TemplateStam
* `this.getRootNode().host`.
*/
readonly domHost: any;
is: string;

/**
* Overrides the default `Polymer.PropertyEffects` implementation to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,5 @@ declare namespace Polymer {
*
* @returns Generated class
*/
function Class(info: PolymerInit): {new(): HTMLElement};
function Class<T>(info: PolymerInit, mixin: (p0: T) => T): {new(): HTMLElement};
}
Loading

0 comments on commit ce5ca6c

Please sign in to comment.