Extends ESLint from @typescript-eslint (#371)

This commit is contained in:
Abdón Rodríguez Davila 2019-08-15 23:51:43 +02:00 committed by Alexander Marks
parent 40f5e43947
commit bb1ad7f281
29 changed files with 91 additions and 82 deletions

View File

@ -1,5 +1,8 @@
extends:
- eslint:recommended
- google
- plugin:@typescript-eslint/eslint-recommended
- plugin:@typescript-eslint/recommended
- plugin:wc/recommended
globals:
goog: false
@ -17,8 +20,16 @@ settings:
wc:
elementBaseClasses: ["BaseElement", "LitElement", "FormElement"]
rules:
# Rules temporally disabled
"@typescript-eslint/explicit-function-return-type": off
# Rules disabled in favor of clang-format
"@typescript-eslint/indent": off
indent: off
max-len: off # clang-format fixes line lengths
max-len: off
"@typescript-eslint/explicit-member-accessibility": [error, {"accessibility": "no-public"}]
no-new: warn
quotes: [error, single, {"avoidEscape": true}]
no-var: error

View File

@ -68,7 +68,7 @@ export abstract class BaseElement extends LitElement {
this.mdcFoundation.init();
}
firstUpdated() {
protected firstUpdated() {
this.createFoundation();
}
}

View File

@ -35,7 +35,7 @@ export abstract class FormElement extends BaseElement {
*/
protected abstract formElement: HTMLElement;
createRenderRoot() {
protected createRenderRoot() {
return this.attachShadow({mode: 'open', delegatesFocus: true});
}
@ -57,7 +57,7 @@ export abstract class FormElement extends BaseElement {
}
}
firstUpdated() {
protected firstUpdated() {
super.firstUpdated();
this.mdcRoot.addEventListener('change', (e) => {
this.dispatchEvent(new Event('change', e));

View File

@ -17,10 +17,12 @@ limitations under the License.
import {PropertyValues} from 'lit-element/lib/updating-element';
export interface Observer {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(value: any, old: any): void;
}
export const observer = (observer: Observer) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(proto: any, propName: PropertyKey) => {
// if we haven't wrapped `updated` in this class, do so
if (!proto.constructor._observers) {
@ -40,6 +42,7 @@ export const observer = (observer: Observer) =>
const observers = proto.constructor._observers;
proto.constructor._observers = new Map();
observers.forEach(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(v: any, k: PropertyKey) => proto.constructor._observers.set(k, v));
}
// set this method

View File

@ -31,6 +31,7 @@ export function findAssignedElement(slot: HTMLSlotElement, selector: string) {
return null;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Constructor<T> = new (...args: any[]) => T;
export function addHasRemoveClass(element: HTMLElement) {

View File

@ -34,11 +34,11 @@ export class ButtonBase extends LitElement {
@property() label = '';
createRenderRoot() {
protected createRenderRoot() {
return this.attachShadow({mode: 'open', delegatesFocus: true});
}
render() {
protected render() {
const classes = {
'mdc-button--raised': this.raised,
'mdc-button--unelevated': this.unelevated,

View File

@ -66,7 +66,7 @@ export class CheckboxBase extends FormElement {
};
}
render() {
protected render() {
return html`
<div class="mdc-checkbox"
@animationend="${this._animationEndHandler}"

View File

@ -55,13 +55,12 @@ export class DrawerBase extends BaseElement {
element.classList.contains(className),
saveFocus: () => {
// Note, casting to avoid cumbersome runtime check.
this._previousFocus =
(this.getRootNode() as any as DocumentOrShadowRoot)
.activeElement as (HTMLElement | null);
this._previousFocus = (this.getRootNode() as ShadowRoot).activeElement as HTMLElement;
},
restoreFocus: () => {
const previousFocus = this._previousFocus && this._previousFocus.focus;
if (previousFocus) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this._previousFocus!.focus();
}
},
@ -94,7 +93,7 @@ export class DrawerBase extends BaseElement {
if (this.mdcFoundation instanceof MDCModalDrawerFoundation) {
this.mdcFoundation.handleScrimClick();
}
};
}
@observer(function(this: DrawerBase, value: boolean) {
if (this.type === '') {
@ -113,7 +112,7 @@ export class DrawerBase extends BaseElement {
@property({reflect: true}) type = '';
render() {
protected render() {
const dismissible = this.type === 'dismissible' || this.type === 'modal';
const modal = this.type === 'modal';
const header = this.hasHeader ? html`
@ -145,14 +144,14 @@ export class DrawerBase extends BaseElement {
// note, we avoid calling `super.firstUpdated()` to control when
// `createFoundation()` is called.
firstUpdated() {
protected firstUpdated() {
this.mdcRoot.addEventListener(
'keydown', (e) => this.mdcFoundation.handleKeydown(e));
this.mdcRoot.addEventListener(
'transitionend', (e) => this.mdcFoundation.handleTransitionEnd(e));
}
updated(changedProperties: PropertyValues) {
protected updated(changedProperties: PropertyValues) {
if (changedProperties.has('type')) {
this.createFoundation();
}

View File

@ -32,11 +32,11 @@ export class FabBase extends LitElement {
@property() label = '';
createRenderRoot() {
protected createRenderRoot() {
return this.attachShadow({mode: 'open', delegatesFocus: true});
}
render() {
protected render() {
const classes = {
'mdc-fab--mini': this.mini,
'mdc-fab--exited': this.exited,

View File

@ -80,7 +80,7 @@ export class FormfieldBase extends BaseElement {
return findAssignedElement(this.slotEl as HTMLSlotElement, '*');
}
render() {
protected render() {
return html`
<div class="mdc-form-field ${classMap({
'mdc-form-field--align-end': this.alignEnd

View File

@ -63,7 +63,7 @@ export class IconButtonToggleBase extends BaseElement {
this.mdcRoot.focus();
}
render() {
protected render() {
return html`
<button
.ripple="${ripple()}"

View File

@ -22,7 +22,7 @@ import {IconButtonToggleBase} from './icon-button-toggle-base';
declare global {
interface HTMLElementTagNameMap {
'mwc-icon-button-toggle': IconButtonToggle
'mwc-icon-button-toggle': IconButtonToggle;
}
}

View File

@ -24,7 +24,7 @@ export class IconButtonBase extends LitElement {
@property({type: String}) label = '';
render() {
protected render() {
return html`<button
.ripple="${ripple()}"
class="mdc-icon-button"

View File

@ -22,7 +22,7 @@ import {style} from './mwc-icon-button-css.js';
declare global {
interface HTMLElementTagNameMap {
'mwc-icon-button': IconButton
'mwc-icon-button': IconButton;
}
}

View File

@ -19,4 +19,5 @@ limitations under the License.
const fontEl = document.createElement('link');
fontEl.rel = 'stylesheet';
fontEl.href = 'https://fonts.googleapis.com/icon?family=Material+Icons';
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
document.head!.appendChild(fontEl);

View File

@ -22,7 +22,7 @@ import {style} from './mwc-icon-host-css.js';
export class Icon extends LitElement {
static styles = style;
render() {
protected render() {
return html`<slot></slot>`;
}
}

View File

@ -64,7 +64,7 @@ export class LinearProgressBase extends BaseElement {
})
closed = false;
render() {
protected render() {
return html`
<div role="progressbar" class="mdc-linear-progress">
<div class="mdc-linear-progress__buffering-dots"></div>

View File

@ -89,6 +89,7 @@ export class RadioBase extends FormElement {
super();
// Selection Controller is only needed for native ShadowDOM
if (!window['ShadyDOM'] || !window['ShadyDOM']['inUse']) {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
this._selectionController = SelectionController.getController(this);
}
}
@ -141,7 +142,7 @@ export class RadioBase extends FormElement {
this.formElement.focus();
}
render() {
protected render() {
return html`
<div class="mdc-radio" .ripple="${ripple()}">
<input
@ -160,7 +161,7 @@ export class RadioBase extends FormElement {
</div>`;
}
firstUpdated() {
protected firstUpdated() {
super.firstUpdated();
// We might not have been able to synchronize this from the checked setter
// earlier, if checked was set before the input was stamped.
@ -264,6 +265,7 @@ export class SelectionController {
const currentFocusedSet = this.focusedSet;
this.focusedSet = set;
if (currentFocusedSet != set && set.selected && set.selected != element) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
set.selected!.focusNative();
}
}

View File

@ -39,7 +39,7 @@ export class RippleBase extends LitElement {
}
// TODO(sorvell) #css: sizing.
render() {
protected render() {
const classes = {
'mdc-ripple-surface--primary': this.primary,
'mdc-ripple-surface--accent': this.accent,

View File

@ -54,6 +54,7 @@ let didApplyRippleStyle = false;
const applyRippleStyle = () => {
didApplyRippleStyle = true;
const part = new NodePart({templateFactory});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
part.appendInto(document.head!);
part.setValue(style);
part.commit();
@ -96,14 +97,14 @@ export const rippleNode = (options: RippleNodeOptions) => {
interactionNode.removeEventListener(type, handler, applyPassive()),
registerDocumentInteractionHandler:
<K extends EventType>(evtType: K, handler: SpecificEventListener<K>) =>
document.documentElement!.addEventListener(
evtType, handler, applyPassive()),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
document.documentElement!.addEventListener(
evtType, handler, applyPassive()),
deregisterDocumentInteractionHandler: <K extends EventType>(
evtType: string, handler: SpecificEventListener<K>) =>
document.documentElement!.removeEventListener(
evtType,
handler as EventListenerOrEventListenerObject,
applyPassive()),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
document.documentElement!.removeEventListener(
evtType, handler as EventListenerOrEventListenerObject, applyPassive()),
registerResizeHandler: (handler: SpecificEventListener<'resize'>) =>
window.addEventListener('resize', handler),
deregisterResizeHandler: (handler: SpecificEventListener<'resize'>) =>
@ -129,13 +130,13 @@ export const ripple =
directive((options: RippleOptions = {}) => (part: PropertyPart) => {
const surfaceNode = part.committer.element as HTMLElement;
const interactionNode = options.interactionNode || surfaceNode;
let rippleFoundation = (part.value as any);
let rippleFoundation = part.value as MDCRippleFoundation | typeof noChange;
// if the interaction node changes, destroy and invalidate the foundation.
const existingInteractionNode =
rippleInteractionNodes.get(rippleFoundation);
if (existingInteractionNode !== undefined &&
existingInteractionNode !== interactionNode) {
rippleFoundation.destroy();
(rippleFoundation as MDCRippleFoundation).destroy();
rippleFoundation = noChange;
}
// make the ripple, if needed
@ -147,15 +148,15 @@ export const ripple =
// otherwise update settings as needed.
} else {
if (options.unbounded !== undefined) {
rippleFoundation.setUnbounded(options.unbounded);
(rippleFoundation as MDCRippleFoundation).setUnbounded(options.unbounded);
}
if (options.disabled !== undefined) {
rippleFoundation.setUnbounded(options.disabled);
(rippleFoundation as MDCRippleFoundation).setUnbounded(options.disabled);
}
}
if (options.active === true) {
rippleFoundation.activate();
(rippleFoundation as MDCRippleFoundation).activate();
} else if (options.active === false) {
rippleFoundation.deactivate();
(rippleFoundation as MDCRippleFoundation).deactivate();
}
});

View File

@ -80,7 +80,7 @@ export class SliderBase extends FormElement {
@property({type: Number}) private _numMarkers = 0;
// TODO(sorvell) #css: needs a default width
render() {
protected render() {
const {value, min, max, step, disabled, discrete, markers, _numMarkers} =
this;
const hostClassInfo = {

View File

@ -59,7 +59,7 @@ export class SnackbarBase extends BaseElement {
*/
private _earlyOpen: boolean|undefined;
render() {
protected render() {
const classes = {
'mdc-snackbar--stacked': this.stacked,
'mdc-snackbar--leading': this.leading,
@ -85,24 +85,15 @@ export class SnackbarBase extends BaseElement {
return {
...addHasRemoveClass(this.mdcRoot),
announce: () => util.announce(this.labelElement),
notifyClosed: (reason: String) => {
notifyClosed: (reason: string) => {
this.isOpen = false;
this.dispatchEvent(new CustomEvent(CLOSED_EVENT, {
bubbles: true,
cancelable: true,
detail: <MDCSnackbarCloseEventDetail> {
reason: reason
}
}));
this.dispatchEvent(new CustomEvent<MDCSnackbarCloseEventDetail>(
CLOSED_EVENT,
{bubbles: true, cancelable: true, detail: {reason: reason}}));
},
notifyClosing: (reason: String) =>
this.dispatchEvent(new CustomEvent(CLOSING_EVENT, {
bubbles: true,
cancelable: true,
detail: <MDCSnackbarCloseEventDetail> {
reason: reason
}
})),
notifyClosing: (reason: string) => this.dispatchEvent(new CustomEvent(
CLOSING_EVENT,
{bubbles: true, cancelable: true, detail: {reason: reason}})),
notifyOpened: () => {
this.isOpen = true;
this.dispatchEvent(
@ -129,22 +120,22 @@ export class SnackbarBase extends BaseElement {
}
}
firstUpdated() {
protected firstUpdated() {
super.firstUpdated();
if (this._earlyOpen === true) {
this.mdcFoundation.open();
}
}
_handleKeydown(e: KeyboardEvent) {
private _handleKeydown(e: KeyboardEvent) {
this.mdcFoundation.handleKeyDown(e);
}
_handleActionClick(e: MouseEvent) {
private _handleActionClick(e: MouseEvent) {
this.mdcFoundation.handleActionButtonClick(e);
}
_handleDismissClick(e: MouseEvent) {
private _handleDismissClick(e: MouseEvent) {
this.mdcFoundation.handleActionIconClick(e);
}
}

View File

@ -42,7 +42,7 @@ export class SwitchBase extends FormElement {
this.mdcFoundation.handleChange(e);
// catch "click" event and sync properties
this.checked = this.formElement.checked;
};
}
protected readonly mdcFoundationClass = MDCSwitchFoundation;
@ -65,7 +65,7 @@ export class SwitchBase extends FormElement {
@query('.mdc-switch__thumb-underlay')
protected rippleNode!: HTMLElementWithRipple;
render() {
protected render() {
return html`
<div class="mdc-switch">
<div class="mdc-switch__track"></div>

View File

@ -62,7 +62,7 @@ export class TabBarBase extends BaseElement {
}
// TODO(sorvell): can scroller be optional for perf?
render() {
protected render() {
return html`
<div class="mdc-tab-bar" role="tablist"
@MDCTab:interacted="${this._handleTabInteraction}"
@ -83,7 +83,7 @@ export class TabBarBase extends BaseElement {
return this._getTabs()[index];
}
createAdapter(): MDCTabBarAdapter {
protected createAdapter(): MDCTabBarAdapter {
return {
scrollTo: (scrollX: number) =>
this.scrollerElement.scrollToPosition(scrollX),
@ -134,7 +134,7 @@ export class TabBarBase extends BaseElement {
},
getFocusedTabIndex: () => {
const tabElements = this._getTabs();
const activeElement = (this as any).getRootNode().activeElement;
const activeElement = (this.getRootNode() as ShadowRoot).activeElement as Tab;
return tabElements.indexOf(activeElement);
},
getIndexOfTabById: (id: string) => {
@ -161,7 +161,7 @@ export class TabBarBase extends BaseElement {
// NOTE: Delay creating foundation until scroller is fully updated.
// This is necessary because the foundation/adapter synchronously addresses
// the scroller element.
firstUpdated() {
protected firstUpdated() {
}
protected _getUpdateComplete() {
return super._getUpdateComplete()

View File

@ -36,7 +36,7 @@ export class TabIndicatorBase extends BaseElement {
@property({type: Boolean}) fade = false;
render() {
protected render() {
const contentClasses = {
'mdc-tab-indicator__content--icon': this.icon,
'material-icons': this.icon,
@ -52,13 +52,13 @@ export class TabIndicatorBase extends BaseElement {
`;
}
updated(changedProperties: PropertyValues) {
protected updated(changedProperties: PropertyValues) {
if (changedProperties.has('fade')) {
this.createFoundation();
}
}
createAdapter(): MDCTabIndicatorAdapter {
protected createAdapter(): MDCTabIndicatorAdapter {
return {
...addHasRemoveClass(this.mdcRoot),
computeContentClientRect: () =>

View File

@ -32,7 +32,7 @@ export class TabScrollerBase extends BaseElement {
@query('.mdc-tab-scroller__scroll-content')
protected scrollContentElement!: HTMLElement;
@eventOptions({passive: true} as EventListenerOptions)
@eventOptions({passive: true})
private _handleInteraction() {
this.mdcFoundation.handleInteraction();
}
@ -43,7 +43,7 @@ export class TabScrollerBase extends BaseElement {
private _scrollbarHeight = -1;
render() {
protected render() {
return html`
<div class="mdc-tab-scroller">
<div class="mdc-tab-scroller__scroll-area"
@ -59,7 +59,7 @@ export class TabScrollerBase extends BaseElement {
`;
}
createAdapter(): MDCTabScrollerAdapter {
protected createAdapter(): MDCTabScrollerAdapter {
return {
...addHasRemoveClass(this.mdcRoot),
eventTargetMatchesSelector: (evtTarget: EventTarget, selector: string) =>

View File

@ -66,7 +66,7 @@ export class TabBase extends BaseElement {
this.mdcFoundation.handleClick();
}
createRenderRoot() {
protected createRenderRoot() {
return this.attachShadow({mode: 'open', delegatesFocus: true});
}
@ -77,13 +77,13 @@ export class TabBase extends BaseElement {
static styles = style;
firstUpdated() {
protected firstUpdated() {
super.firstUpdated();
// create an unique id
this.id = this.id || `mdc-tab-${++tabIdCounter}`;
}
render() {
protected render() {
const classes = {
'mdc-tab--min-width': this.minWidth,
'mdc-tab--stacked': this.stacked,
@ -115,14 +115,14 @@ export class TabBase extends BaseElement {
</button>`;
}
renderIndicator() {
protected renderIndicator() {
return html`<mwc-tab-indicator
.icon="${this.indicatorIcon}"
.fade="${this.isFadingIndicator}"></mwc-tab-indicator>`;
}
createAdapter(): MDCTabAdapter {
protected createAdapter(): MDCTabAdapter {
return {
...addHasRemoveClass(this.mdcRoot),
setAttr: (attr: string, value: string) =>

View File

@ -65,7 +65,7 @@ export class TopAppBarBase extends BaseElement {
// TODO(sorvell): MDC decorates the navigation icon and action items with
// ripples. Since these are slotted items here, the assumption is that the
// user brings a web component with a ripple if rippling is desired.
render() {
protected render() {
const classes = {
'mdc-top-app-bar--fixed':
this.type === 'fixed' || this.type === 'prominentFixed',
@ -123,10 +123,10 @@ export class TopAppBarBase extends BaseElement {
// override that prevents `super.firstUpdated` since we are controlling when
// `createFoundation` is called.
firstUpdated() {
protected firstUpdated() {
}
updated(changedProperties: PropertyValues) {
protected updated(changedProperties: PropertyValues) {
// update foundation if `type` or `scrollTarget` changes
if (changedProperties.has('type') ||
changedProperties.has('scrollTarget')) {
@ -163,7 +163,7 @@ export class TopAppBarBase extends BaseElement {
}
}
createFoundation() {
protected createFoundation() {
super.createFoundation();
const windowScroller = this.scrollTarget === window;
// we add support for top-app-bar's tied to an element scroller.

View File

@ -71,7 +71,7 @@ export class TestFixture extends LitElement {
}
}
render() {
protected render() {
return html`
${this.shouldAttachContents ? this.template : ''}
`;