Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow mixin classes to have members added via .prototype calls. #799

Merged
merged 3 commits into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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