Skip to content

Commit ce5ca6c

Browse files
authored
Merge pull request #799 from Polymer/mixin-prototype
Allow mixin classes to have members added via .prototype calls.
2 parents 1e32fc3 + fe0a724 commit ce5ca6c

22 files changed

Lines changed: 296 additions & 36 deletions

File tree

packages/analyzer/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

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

1113
## [3.1.3] - 2018-10-15

packages/analyzer/src/javascript/class-scanner.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,16 @@ export class ClassScanner implements JavaScriptScanner {
7676
document: JavaScriptDocument,
7777
visit: (visitor: Visitor) => Promise<void>) {
7878
const classFinder = new ClassFinder(document);
79-
const mixinFinder = new MixinVisitor(document);
8079
const elementDefinitionFinder =
8180
new CustomElementsDefineCallFinder(document);
8281
const prototypeMemberFinder = new PrototypeMemberFinder(document);
82+
await visit(prototypeMemberFinder);
83+
const mixinFinder = new MixinVisitor(document, prototypeMemberFinder);
8384
// Find all classes and all calls to customElements.define()
8485
await Promise.all([
8586
visit(classFinder),
8687
visit(elementDefinitionFinder),
8788
visit(mixinFinder),
88-
visit(prototypeMemberFinder),
8989
]);
9090
const mixins = mixinFinder.mixins;
9191

@@ -424,7 +424,7 @@ interface CustomElementDefinition {
424424
definition?: ElementDefineCall;
425425
}
426426

427-
class PrototypeMemberFinder implements Visitor {
427+
export class PrototypeMemberFinder implements Visitor {
428428
readonly members = new MapWithDefault<string, {
429429
methods: Map<string, ScannedMethod>,
430430
properties: Map<string, ScannedProperty>
@@ -505,16 +505,16 @@ class PrototypeMemberFinder implements Visitor {
505505
}
506506

507507
if (jsdoc.hasTag(jsdocAnn, 'function')) {
508-
const prop =
508+
const method =
509509
this._createMethodFromExpression(node.property.name, node, jsdocAnn);
510-
if (prop) {
511-
this._addMethodToClass(cls, prop);
510+
if (method) {
511+
this._addMethodToClass(cls, method);
512512
}
513513
} else {
514-
const method = this._createPropertyFromExpression(
514+
const prop = this._createPropertyFromExpression(
515515
node.property.name, node, jsdocAnn);
516-
if (method) {
517-
this._addPropertyToClass(cls, method);
516+
if (prop) {
517+
this._addPropertyToClass(cls, prop);
518518
}
519519
}
520520
}

packages/analyzer/src/polymer/polymer2-mixin-scanner.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {NodePath} from '@babel/traverse';
1616
import * as babel from '@babel/types';
1717

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

39-
constructor(document: JavaScriptDocument) {
40+
constructor(
41+
document: JavaScriptDocument,
42+
prototypeMemberFinder: PrototypeMemberFinder) {
4043
this._document = document;
44+
this._prototypeMemberFinder = prototypeMemberFinder;
4145
}
4246

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

162-
return mixin;
166+
// Also add members that were described like:
167+
// /** @type {string} */
168+
// MixinClass.prototype.foo;
169+
const name = getIdentifierName(node.id);
170+
if (name !== undefined) {
171+
const prototypeMembers = this._prototypeMemberFinder.members.get(name);
172+
if (prototypeMembers !== undefined) {
173+
for (const [, property] of prototypeMembers.properties) {
174+
mixin.addProperty(property);
175+
}
176+
for (const [, method] of prototypeMembers.methods) {
177+
mixin.addMethod(method);
178+
}
179+
}
180+
}
163181
}
164182
}
165183

packages/gen-typescript-declarations/scripts/fixtures.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ https://github.com/PolymerElements/paper-button.git v2.0.0 paper-button-2
44
https://github.com/PolymerElements/paper-button.git f644abdfc660f58b6535134ae9a0c16fa7ccaf16 paper-button-3
55
https://github.com/PolymerElements/paper-menu-button.git v2.0.0 paper-menu-button-2
66
https://github.com/PolymerElements/paper-menu-button.git ab4885daa67d09a929c8209972e20fbf56014543 paper-menu-button-3
7-
https://github.com/Polymer/polymer.git 50ba80b864d4843d4e59cfdddeab6efdf280a2ec polymer-2
7+
https://github.com/Polymer/polymer.git 646355bef43f4559006675452e4248560a614737 polymer-2
88
https://github.com/Polymer/polymer.git 7791ee9e8655b6a55ec6e65419d21e9e7eb0a581 polymer-3

packages/gen-typescript-declarations/src/test/goldens/polymer-2/lib/legacy/class.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,5 @@ declare namespace Polymer {
9494
*
9595
* @returns Generated class
9696
*/
97-
function Class(info: PolymerInit): {new(): HTMLElement};
97+
function Class<T>(info: PolymerInit, mixin: (p0: T) => T): {new(): HTMLElement};
9898
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* DO NOT EDIT
3+
*
4+
* This file was automatically generated by
5+
* https://github.com/Polymer/tools/tree/master/packages/gen-typescript-declarations
6+
*
7+
* To modify these typings, edit the source file(s):
8+
* lib/legacy/legacy-data-mixin.html
9+
*/
10+
11+
12+
// tslint:disable:variable-name Describing an API that's defined elsewhere.
13+
// tslint:disable:no-any describes the API as best we are able today
14+
15+
/// <reference path="class.d.ts" />
16+
/// <reference path="../../polymer.d.ts" />
17+
/// <reference path="../utils/mixin.d.ts" />
18+
/// <reference path="../utils/templatize.d.ts" />
19+
20+
declare class UndefinedArgumentError extends Error {
21+
constructor(message: any, arg: any);
22+
}
23+
24+
declare namespace Polymer {
25+
26+
27+
/**
28+
* Mixin to selectively add back Polymer 1.x's `undefined` rules
29+
* governing when observers & computing functions run based
30+
* on all arguments being defined (reference https://www.polymer-project.org/1.0/docs/devguide/observers#multi-property-observers).
31+
*
32+
* When loaded, all legacy elements (defined with `Polymer({...})`)
33+
* will have the mixin applied. The mixin only restores legacy data handling
34+
* if `_legacyUndefinedCheck: true` is set on the element's prototype.
35+
*
36+
* This mixin is intended for use to help migration from Polymer 1.x to
37+
* 2.x+ by allowing legacy code to work while identifying observers and
38+
* computing functions that need undefined checks to work without
39+
* the mixin in Polymer 2.
40+
*/
41+
function LegacyDataMixin<T extends new (...args: any[]) => {}>(base: T): T & LegacyDataMixinConstructor;
42+
43+
interface LegacyDataMixinConstructor {
44+
new(...args: any[]): LegacyDataMixin;
45+
46+
/**
47+
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
48+
* catch `UndefinedArgumentError`s and warn.
49+
*
50+
* @param templateInfo Template metadata to add effect to
51+
* @param prop Property that should trigger the effect
52+
* @param effect Effect metadata object
53+
*/
54+
_addTemplatePropertyEffect(templateInfo: object|null, prop: string, effect?: object|null): void;
55+
}
56+
57+
interface LegacyDataMixin {
58+
readonly _legacyUndefinedCheck: any;
59+
60+
/**
61+
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
62+
* catch `UndefinedArgumentError`s and warn.
63+
*
64+
* @param property Property that should trigger the effect
65+
* @param type Effect type, from this.PROPERTY_EFFECT_TYPES
66+
* @param effect Effect metadata object
67+
*/
68+
_addPropertyEffect(property: string, type: string, effect?: object|null): void;
69+
}
70+
}
71+
72+
declare class LegacyDataMixin extends superClass {
73+
74+
/**
75+
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
76+
* catch `UndefinedArgumentError`s and warn.
77+
*
78+
* @param templateInfo Template metadata to add effect to
79+
* @param prop Property that should trigger the effect
80+
* @param effect Effect metadata object
81+
*/
82+
static _addTemplatePropertyEffect(templateInfo: object|null, prop: string, effect?: object|null): void;
83+
84+
/**
85+
* Overrides `Polyer.PropertyEffects` to wrap effect functions to
86+
* catch `UndefinedArgumentError`s and warn.
87+
*
88+
* @param property Property that should trigger the effect
89+
* @param type Effect type, from this.PROPERTY_EFFECT_TYPES
90+
* @param effect Effect metadata object
91+
*/
92+
_addPropertyEffect(property: string, type: string, effect?: object|null): void;
93+
}

packages/gen-typescript-declarations/src/test/goldens/polymer-2/lib/legacy/legacy-element-mixin.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,16 @@ declare namespace Polymer {
3737
}
3838

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

4341
/**
4442
* Return the element whose local dom within which this element
4543
* is contained. This is a shorthand for
4644
* `this.getRootNode().host`.
4745
*/
4846
readonly domHost: any;
47+
isAttached: boolean;
48+
_debouncers: {[key: string]: Function|null};
49+
is: string;
4950

5051
/**
5152
* Overrides the default `Polymer.PropertyEffects` implementation to

packages/gen-typescript-declarations/src/test/goldens/polymer-2/lib/mixins/element-mixin.d.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ declare namespace Polymer {
104104
* find the template.
105105
*/
106106
_finalizeClass(): void;
107+
_prepareTemplate(): void;
107108

108109
/**
109110
* Creates observers for the given `observers` array.
@@ -227,11 +228,4 @@ declare namespace Polymer {
227228
*/
228229
resolveUrl(url: string, base?: string): string;
229230
}
230-
231-
/**
232-
* Provides basic tracking of element definitions (registrations) and
233-
* instance counts.
234-
*/
235-
namespace telemetry {
236-
}
237231
}

packages/gen-typescript-declarations/src/test/goldens/polymer-2/lib/mixins/properties-mixin.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// tslint:disable:no-any describes the API as best we are able today
1414

1515
/// <reference path="../utils/boot.d.ts" />
16+
/// <reference path="../utils/telemetry.d.ts" />
1617
/// <reference path="../utils/mixin.d.ts" />
1718
/// <reference path="properties-changed.d.ts" />
1819

packages/gen-typescript-declarations/src/test/goldens/polymer-2/lib/utils/debounce.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
declare namespace Polymer {
2020

2121
class Debouncer {
22-
constructor();
2322

2423
/**
2524
* Creates a debouncer if no debouncer is passed as a parameter

0 commit comments

Comments
 (0)