From 4e99e515bf7ec08cac00ea67e978138835653bbf Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Sat, 9 Feb 2019 02:30:55 -0800 Subject: [PATCH 01/10] feat(auto-init): Convert JS to TypeScript Refs #4225 --- packages/mdc-auto-init/{index.js => index.ts} | 31 ++++++++++++------- packages/mdc-auto-init/package.json | 3 ++ scripts/webpack/js-bundle-factory.js | 2 +- 3 files changed, 23 insertions(+), 13 deletions(-) rename packages/mdc-auto-init/{index.js => index.ts} (78%) diff --git a/packages/mdc-auto-init/index.js b/packages/mdc-auto-init/index.ts similarity index 78% rename from packages/mdc-auto-init/index.js rename to packages/mdc-auto-init/index.ts index a76766fcac6..1c6492567ed 100644 --- a/packages/mdc-auto-init/index.js +++ b/packages/mdc-auto-init/index.ts @@ -21,16 +21,18 @@ * THE SOFTWARE. */ +// tslint:disable:only-arrow-functions + const registry = Object.create(null); -const CONSOLE_WARN = console.warn.bind(console); +const CONSOLE_WARN = console.warn.bind(console); // tslint:disable-line:no-console -function _emit(evtType, evtData, shouldBubble = false) { +function _emit(evtType: string, evtData: object, shouldBubble = false) { let evt; if (typeof CustomEvent === 'function') { evt = new CustomEvent(evtType, { - detail: evtData, bubbles: shouldBubble, + detail: evtData, }); } else { evt = document.createEvent('CustomEvent'); @@ -41,23 +43,25 @@ function _emit(evtType, evtData, shouldBubble = false) { } /** - * Auto-initializes all mdc components on a page. + * Auto-initializes all MDC components on a page. */ -export default function mdcAutoInit(root = document, warn = CONSOLE_WARN) { +function mdcAutoInit(root = document, warn = CONSOLE_WARN) { const components = []; - const nodes = root.querySelectorAll('[data-mdc-auto-init]'); - for (let i = 0, node; (node = nodes[i]); i++) { + const nodes: HTMLElement[] = [].slice.call(root.querySelectorAll('[data-mdc-auto-init]')); + + for (const node of nodes) { const ctorName = node.dataset.mdcAutoInit; if (!ctorName) { throw new Error('(mdc-auto-init) Constructor name must be given.'); } - const Ctor = registry[ctorName]; + const Ctor = registry[ctorName]; // tslint:disable-line:variable-name if (typeof Ctor !== 'function') { throw new Error( `(mdc-auto-init) Could not find constructor in registry for ${ctorName}`); } + // @ts-ignore if (node[ctorName]) { warn(`(mdc-auto-init) Component already initialized for ${node}. Skipping...`); continue; @@ -66,10 +70,10 @@ export default function mdcAutoInit(root = document, warn = CONSOLE_WARN) { // TODO: Should we make an eslint rule for an attachTo() static method? const component = Ctor.attachTo(node); Object.defineProperty(node, ctorName, { + configurable: true, + enumerable: false, value: component, writable: false, - enumerable: false, - configurable: true, }); components.push(component); } @@ -78,7 +82,8 @@ export default function mdcAutoInit(root = document, warn = CONSOLE_WARN) { return components; } -mdcAutoInit.register = function(componentName, Ctor, warn = CONSOLE_WARN) { +// tslint:disable-next-line:variable-name +mdcAutoInit.register = function(componentName: string, Ctor: Function, warn = CONSOLE_WARN) { if (typeof Ctor !== 'function') { throw new Error(`(mdc-auto-init) Invalid Ctor value ${Ctor}. Expected function`); } @@ -90,10 +95,12 @@ mdcAutoInit.register = function(componentName, Ctor, warn = CONSOLE_WARN) { registry[componentName] = Ctor; }; -mdcAutoInit.deregister = function(componentName) { +mdcAutoInit.deregister = function(componentName: string) { delete registry[componentName]; }; mdcAutoInit.deregisterAll = function() { Object.keys(registry).forEach(this.deregister, this); }; + +export {mdcAutoInit as default, mdcAutoInit}; diff --git a/packages/mdc-auto-init/package.json b/packages/mdc-auto-init/package.json index d6074449fc8..2c09174a18e 100644 --- a/packages/mdc-auto-init/package.json +++ b/packages/mdc-auto-init/package.json @@ -7,5 +7,8 @@ "repository": { "type": "git", "url": "https://github.com/material-components/material-components-web.git" + }, + "dependencies": { + "@material/base": "^0.41.0" } } diff --git a/scripts/webpack/js-bundle-factory.js b/scripts/webpack/js-bundle-factory.js index f91236916ed..0ee4ec5deb1 100644 --- a/scripts/webpack/js-bundle-factory.js +++ b/scripts/webpack/js-bundle-factory.js @@ -153,7 +153,7 @@ class JsBundleFactory { bundleName: 'main-js-a-la-carte', chunks: { animation: getAbsolutePath('/packages/mdc-animation/index.ts'), - autoInit: getAbsolutePath('/packages/mdc-auto-init/index.js'), + autoInit: getAbsolutePath('/packages/mdc-auto-init/index.ts'), base: getAbsolutePath('/packages/mdc-base/index.ts'), checkbox: getAbsolutePath('/packages/mdc-checkbox/index.ts'), chips: getAbsolutePath('/packages/mdc-chips/index.ts'), From e9690cf3bc4b0bb3bd53e3c0cc1377e5b4d85064 Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Tue, 12 Feb 2019 17:37:21 -0800 Subject: [PATCH 02/10] WIP: Stronger typing --- packages/mdc-auto-init/index.ts | 65 ++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index 1c6492567ed..a157dd7bff0 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -23,14 +23,60 @@ // tslint:disable:only-arrow-functions -const registry = Object.create(null); +import {MDCComponent} from '@material/base/component'; +import {MDCFoundation} from '@material/base/foundation'; + +export type MDCAutoInitKey = ( + 'MDCCheckbox' | + 'MDCChip' | + 'MDCChipSet' | + 'MDCDialog' | + 'MDCDrawer' | + 'MDCFloatingLabel' | + 'MDCFormField' | + 'MDCGridList' | + 'MDCIconButtonToggle' | + 'MDCIconToggle' | + 'MDCLineRipple' | + 'MDCLinearProgress' | + 'MDCList' | + 'MDCMenu' | + 'MDCMenuSurface' | + 'MDCNotchedOutline' | + 'MDCRadio' | + 'MDCRipple' | + 'MDCSelect' | + 'MDCSlider' | + 'MDCSnackbar' | + 'MDCSwitch' | + 'MDCTabBar' | + 'MDCTextField' | + 'MDCToolbar' | + 'MDCTopAppBar' +); + +export type MDCAutoInitElement = HTMLElement & { + [K in MDCAutoInitKey]?: string; +}; + +interface ComponentClass { + // tslint:disable-next-line:no-any a component can pass in anything it needs to the constructor + new(root: Element, foundation?: F, ...args: any[]): MDCComponent; + attachTo(root: Element): MDCComponent; +} + +type Registry = { + [K in MDCAutoInitKey]?: ComponentClass; +}; + +const registry: Registry = {}; const CONSOLE_WARN = console.warn.bind(console); // tslint:disable-line:no-console -function _emit(evtType: string, evtData: object, shouldBubble = false) { +function _emit(evtType: string, evtData: T, shouldBubble = false) { let evt; if (typeof CustomEvent === 'function') { - evt = new CustomEvent(evtType, { + evt = new CustomEvent(evtType, { bubbles: shouldBubble, detail: evtData, }); @@ -47,10 +93,10 @@ function _emit(evtType: string, evtData: object, shouldBubble = false) { */ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { const components = []; - const nodes: HTMLElement[] = [].slice.call(root.querySelectorAll('[data-mdc-auto-init]')); + const nodes: MDCAutoInitElement[] = [].slice.call(root.querySelectorAll('[data-mdc-auto-init]')); for (const node of nodes) { - const ctorName = node.dataset.mdcAutoInit; + const ctorName = node.getAttribute('data-mdc-auto-init') as MDCAutoInitKey | null; if (!ctorName) { throw new Error('(mdc-auto-init) Constructor name must be given.'); } @@ -61,13 +107,13 @@ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { `(mdc-auto-init) Could not find constructor in registry for ${ctorName}`); } - // @ts-ignore if (node[ctorName]) { warn(`(mdc-auto-init) Component already initialized for ${node}. Skipping...`); continue; } // TODO: Should we make an eslint rule for an attachTo() static method? + // See https://github.com/Microsoft/TypeScript/issues/14600 for discussion of static interface support in TS const component = Ctor.attachTo(node); Object.defineProperty(node, ctorName, { configurable: true, @@ -83,7 +129,7 @@ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { } // tslint:disable-next-line:variable-name -mdcAutoInit.register = function(componentName: string, Ctor: Function, warn = CONSOLE_WARN) { +mdcAutoInit.register = function(componentName: MDCAutoInitKey, Ctor: ComponentClass, warn = CONSOLE_WARN) { if (typeof Ctor !== 'function') { throw new Error(`(mdc-auto-init) Invalid Ctor value ${Ctor}. Expected function`); } @@ -95,12 +141,13 @@ mdcAutoInit.register = function(componentName: string, Ctor: Function, warn = CO registry[componentName] = Ctor; }; -mdcAutoInit.deregister = function(componentName: string) { +mdcAutoInit.deregister = function(componentName: MDCAutoInitKey) { delete registry[componentName]; }; mdcAutoInit.deregisterAll = function() { - Object.keys(registry).forEach(this.deregister, this); + const keys = Object.keys(registry) as MDCAutoInitKey[]; + keys.forEach(this.deregister, this); }; export {mdcAutoInit as default, mdcAutoInit}; From 6b6f7fbf66df5a41defc6ddd48eedc3d2fe8067c Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Tue, 12 Feb 2019 17:38:19 -0800 Subject: [PATCH 03/10] WIP: Make Istanbul happy --- packages/mdc-auto-init/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index a157dd7bff0..58596397677 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -88,6 +88,7 @@ function _emit(evtType: string, evtData: T, shouldBubble = fal document.dispatchEvent(evt); } +/* istanbul ignore next: optional argument is not a branch statement */ /** * Auto-initializes all MDC components on a page. */ From 78e0b7fb159bf9b87e0beb77d73b95622b4084ef Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Tue, 12 Feb 2019 18:41:15 -0800 Subject: [PATCH 04/10] WIP: Add `types.ts` for public exports --- packages/mdc-auto-init/index.ts | 35 ++------------------- packages/mdc-auto-init/types.ts | 55 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 33 deletions(-) create mode 100644 packages/mdc-auto-init/types.ts diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index 58596397677..1e708437e46 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -25,39 +25,7 @@ import {MDCComponent} from '@material/base/component'; import {MDCFoundation} from '@material/base/foundation'; - -export type MDCAutoInitKey = ( - 'MDCCheckbox' | - 'MDCChip' | - 'MDCChipSet' | - 'MDCDialog' | - 'MDCDrawer' | - 'MDCFloatingLabel' | - 'MDCFormField' | - 'MDCGridList' | - 'MDCIconButtonToggle' | - 'MDCIconToggle' | - 'MDCLineRipple' | - 'MDCLinearProgress' | - 'MDCList' | - 'MDCMenu' | - 'MDCMenuSurface' | - 'MDCNotchedOutline' | - 'MDCRadio' | - 'MDCRipple' | - 'MDCSelect' | - 'MDCSlider' | - 'MDCSnackbar' | - 'MDCSwitch' | - 'MDCTabBar' | - 'MDCTextField' | - 'MDCToolbar' | - 'MDCTopAppBar' -); - -export type MDCAutoInitElement = HTMLElement & { - [K in MDCAutoInitKey]?: string; -}; +import {MDCAutoInitElement, MDCAutoInitKey} from './types'; interface ComponentClass { // tslint:disable-next-line:no-any a component can pass in anything it needs to the constructor @@ -152,3 +120,4 @@ mdcAutoInit.deregisterAll = function() { }; export {mdcAutoInit as default, mdcAutoInit}; +export * from './types'; diff --git a/packages/mdc-auto-init/types.ts b/packages/mdc-auto-init/types.ts new file mode 100644 index 00000000000..b8164a35e92 --- /dev/null +++ b/packages/mdc-auto-init/types.ts @@ -0,0 +1,55 @@ +/** + * @license + * Copyright 2019 Google Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +export type MDCAutoInitKey = ( + 'MDCCheckbox' | + 'MDCChip' | + 'MDCChipSet' | + 'MDCDialog' | + 'MDCDrawer' | + 'MDCFloatingLabel' | + 'MDCFormField' | + 'MDCGridList' | + 'MDCIconButtonToggle' | + 'MDCIconToggle' | + 'MDCLineRipple' | + 'MDCLinearProgress' | + 'MDCList' | + 'MDCMenu' | + 'MDCMenuSurface' | + 'MDCNotchedOutline' | + 'MDCRadio' | + 'MDCRipple' | + 'MDCSelect' | + 'MDCSlider' | + 'MDCSnackbar' | + 'MDCSwitch' | + 'MDCTabBar' | + 'MDCTextField' | + 'MDCToolbar' | + 'MDCTopAppBar' +); + +export type MDCAutoInitElement = HTMLElement & { + [K in MDCAutoInitKey]?: string; +}; From 50f256c1c34e29ce930f5d858da3aeabe6b2c14c Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Wed, 13 Feb 2019 19:50:00 -0800 Subject: [PATCH 05/10] WIP: Rename `Ctor` to `Constructor` and add comment explaining `tslint:disable` --- packages/mdc-auto-init/index.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index 1e708437e46..368872a555a 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -70,8 +70,8 @@ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { throw new Error('(mdc-auto-init) Constructor name must be given.'); } - const Ctor = registry[ctorName]; // tslint:disable-line:variable-name - if (typeof Ctor !== 'function') { + const Constructor = registry[ctorName]; // tslint:disable-line:variable-name + if (typeof Constructor !== 'function') { throw new Error( `(mdc-auto-init) Could not find constructor in registry for ${ctorName}`); } @@ -83,7 +83,7 @@ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { // TODO: Should we make an eslint rule for an attachTo() static method? // See https://github.com/Microsoft/TypeScript/issues/14600 for discussion of static interface support in TS - const component = Ctor.attachTo(node); + const component = Constructor.attachTo(node); Object.defineProperty(node, ctorName, { configurable: true, enumerable: false, @@ -97,17 +97,18 @@ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { return components; } +// Constructor is PascalCased because it is a direct reference to a class, rather than an instance of a class. // tslint:disable-next-line:variable-name -mdcAutoInit.register = function(componentName: MDCAutoInitKey, Ctor: ComponentClass, warn = CONSOLE_WARN) { - if (typeof Ctor !== 'function') { - throw new Error(`(mdc-auto-init) Invalid Ctor value ${Ctor}. Expected function`); +mdcAutoInit.register = function(componentName: MDCAutoInitKey, Constructor: ComponentClass, warn = CONSOLE_WARN) { + if (typeof Constructor !== 'function') { + throw new Error(`(mdc-auto-init) Invalid Ctor value ${Constructor}. Expected function`); } if (registry[componentName]) { warn( - `(mdc-auto-init) Overriding registration for ${componentName} with ${Ctor}. ` + + `(mdc-auto-init) Overriding registration for ${componentName} with ${Constructor}. ` + `Was: ${registry[componentName]}`); } - registry[componentName] = Ctor; + registry[componentName] = Constructor; }; mdcAutoInit.deregister = function(componentName: MDCAutoInitKey) { From cbd6218fc5e948f6b79f14f9a0fe1c907d9e27f5 Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Wed, 13 Feb 2019 19:54:08 -0800 Subject: [PATCH 06/10] WIP: Condense import statements into one line --- packages/mdc-auto-init/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index 368872a555a..203816eef0f 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -23,8 +23,7 @@ // tslint:disable:only-arrow-functions -import {MDCComponent} from '@material/base/component'; -import {MDCFoundation} from '@material/base/foundation'; +import {MDCComponent, MDCFoundation} from '@material/base/index'; import {MDCAutoInitElement, MDCAutoInitKey} from './types'; interface ComponentClass { From eb01f1881a4dc4a2b23788ff20176914469b0b6a Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Thu, 14 Feb 2019 10:06:21 -0800 Subject: [PATCH 07/10] WIP: Remove `MDCAutoInitKey` type; use `string` instead (so clients can register custom components) --- packages/mdc-auto-init/index.ts | 24 +++++++------- packages/mdc-auto-init/types.ts | 55 --------------------------------- 2 files changed, 11 insertions(+), 68 deletions(-) delete mode 100644 packages/mdc-auto-init/types.ts diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index 203816eef0f..18bcba6a74b 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -24,7 +24,6 @@ // tslint:disable:only-arrow-functions import {MDCComponent, MDCFoundation} from '@material/base/index'; -import {MDCAutoInitElement, MDCAutoInitKey} from './types'; interface ComponentClass { // tslint:disable-next-line:no-any a component can pass in anything it needs to the constructor @@ -32,9 +31,9 @@ interface ComponentClass { attachTo(root: Element): MDCComponent; } -type Registry = { - [K in MDCAutoInitKey]?: ComponentClass; -}; +interface Registry { + [key: string]: ComponentClass; +} const registry: Registry = {}; @@ -59,12 +58,12 @@ function _emit(evtType: string, evtData: T, shouldBubble = fal /** * Auto-initializes all MDC components on a page. */ -function mdcAutoInit(root = document, warn = CONSOLE_WARN) { +export function mdcAutoInit(root = document, warn = CONSOLE_WARN) { const components = []; - const nodes: MDCAutoInitElement[] = [].slice.call(root.querySelectorAll('[data-mdc-auto-init]')); + const nodes: Element[] = [].slice.call(root.querySelectorAll('[data-mdc-auto-init]')); for (const node of nodes) { - const ctorName = node.getAttribute('data-mdc-auto-init') as MDCAutoInitKey | null; + const ctorName = node.getAttribute('data-mdc-auto-init'); if (!ctorName) { throw new Error('(mdc-auto-init) Constructor name must be given.'); } @@ -75,7 +74,7 @@ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { `(mdc-auto-init) Could not find constructor in registry for ${ctorName}`); } - if (node[ctorName]) { + if (Object.getOwnPropertyDescriptor(node, ctorName)) { warn(`(mdc-auto-init) Component already initialized for ${node}. Skipping...`); continue; } @@ -98,7 +97,7 @@ function mdcAutoInit(root = document, warn = CONSOLE_WARN) { // Constructor is PascalCased because it is a direct reference to a class, rather than an instance of a class. // tslint:disable-next-line:variable-name -mdcAutoInit.register = function(componentName: MDCAutoInitKey, Constructor: ComponentClass, warn = CONSOLE_WARN) { +mdcAutoInit.register = function(componentName: string, Constructor: ComponentClass, warn = CONSOLE_WARN) { if (typeof Constructor !== 'function') { throw new Error(`(mdc-auto-init) Invalid Ctor value ${Constructor}. Expected function`); } @@ -110,14 +109,13 @@ mdcAutoInit.register = function(componentName: MDCAutoInitKey, Constructor: Comp registry[componentName] = Constructor; }; -mdcAutoInit.deregister = function(componentName: MDCAutoInitKey) { +mdcAutoInit.deregister = function(componentName: string) { delete registry[componentName]; }; mdcAutoInit.deregisterAll = function() { - const keys = Object.keys(registry) as MDCAutoInitKey[]; + const keys = Object.keys(registry) as string[]; keys.forEach(this.deregister, this); }; -export {mdcAutoInit as default, mdcAutoInit}; -export * from './types'; +export default mdcAutoInit; diff --git a/packages/mdc-auto-init/types.ts b/packages/mdc-auto-init/types.ts deleted file mode 100644 index b8164a35e92..00000000000 --- a/packages/mdc-auto-init/types.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @license - * Copyright 2019 Google Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -export type MDCAutoInitKey = ( - 'MDCCheckbox' | - 'MDCChip' | - 'MDCChipSet' | - 'MDCDialog' | - 'MDCDrawer' | - 'MDCFloatingLabel' | - 'MDCFormField' | - 'MDCGridList' | - 'MDCIconButtonToggle' | - 'MDCIconToggle' | - 'MDCLineRipple' | - 'MDCLinearProgress' | - 'MDCList' | - 'MDCMenu' | - 'MDCMenuSurface' | - 'MDCNotchedOutline' | - 'MDCRadio' | - 'MDCRipple' | - 'MDCSelect' | - 'MDCSlider' | - 'MDCSnackbar' | - 'MDCSwitch' | - 'MDCTabBar' | - 'MDCTextField' | - 'MDCToolbar' | - 'MDCTopAppBar' -); - -export type MDCAutoInitElement = HTMLElement & { - [K in MDCAutoInitKey]?: string; -}; From 8aae7e31145070abd568ff7ca0afa6b33ce113fc Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Thu, 14 Feb 2019 10:36:57 -0800 Subject: [PATCH 08/10] WIP: Remove old TODO --- packages/mdc-auto-init/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index 18bcba6a74b..287cc771902 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -79,8 +79,6 @@ export function mdcAutoInit(root = document, warn = CONSOLE_WARN) { continue; } - // TODO: Should we make an eslint rule for an attachTo() static method? - // See https://github.com/Microsoft/TypeScript/issues/14600 for discussion of static interface support in TS const component = Constructor.attachTo(node); Object.defineProperty(node, ctorName, { configurable: true, From 3c83f311fe1260a48462747eb850ffb8e5ff4a7a Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Thu, 14 Feb 2019 10:58:12 -0800 Subject: [PATCH 09/10] Revert "WIP: Remove old TODO" This reverts commit 8aae7e31145070abd568ff7ca0afa6b33ce113fc. --- packages/mdc-auto-init/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/mdc-auto-init/index.ts b/packages/mdc-auto-init/index.ts index 287cc771902..18bcba6a74b 100644 --- a/packages/mdc-auto-init/index.ts +++ b/packages/mdc-auto-init/index.ts @@ -79,6 +79,8 @@ export function mdcAutoInit(root = document, warn = CONSOLE_WARN) { continue; } + // TODO: Should we make an eslint rule for an attachTo() static method? + // See https://github.com/Microsoft/TypeScript/issues/14600 for discussion of static interface support in TS const component = Constructor.attachTo(node); Object.defineProperty(node, ctorName, { configurable: true, From 5d3f489c2b9898356da5337a2a60584007b58960 Mon Sep 17 00:00:00 2001 From: Andy Dvorak Date: Thu, 14 Feb 2019 10:59:08 -0800 Subject: [PATCH 10/10] WIP: Add unit test for missing static `attachTo()` method --- test/unit/mdc-auto-init/mdc-auto-init.test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/unit/mdc-auto-init/mdc-auto-init.test.js b/test/unit/mdc-auto-init/mdc-auto-init.test.js index c531ab266ba..9347f078a4b 100644 --- a/test/unit/mdc-auto-init/mdc-auto-init.test.js +++ b/test/unit/mdc-auto-init/mdc-auto-init.test.js @@ -36,6 +36,12 @@ class FakeComponent { } } +class InvalidComponent { + constructor(node) { + this.node = node; + } +} + const createFixture = () => bel`

Fake Element

@@ -48,6 +54,12 @@ const setupTest = () => { return createFixture(); }; +const setupInvalidTest = () => { + mdcAutoInit.deregisterAll(); + mdcAutoInit.register('InvalidComponent', InvalidComponent); + return createFixture(); +}; + suite('MDCAutoInit'); test('calls attachTo() on components registered for identifier on nodes w/ data-mdc-auto-init attr', () => { @@ -57,6 +69,11 @@ test('calls attachTo() on components registered for identifier on nodes w/ data- assert.isOk(root.querySelector('.mdc-fake').FakeComponent instanceof FakeComponent); }); +test('throws when attachTo() is missing', () => { + const root = setupInvalidTest(); + assert.throws(() => mdcAutoInit(root)); +}); + test('passes the node where "data-mdc-auto-init" was found to attachTo()', () => { const root = setupTest(); mdcAutoInit(root);