From 5cefa7c1399a53587bca681a7ed193fb309d940e Mon Sep 17 00:00:00 2001 From: jason Date: Sun, 10 Dec 2017 20:43:00 +0300 Subject: [PATCH 1/4] Added type annotation to helpers, added ts declaration files for angular and angular/demo modules --- app/angular/demo.d.ts | 4 + app/angular/index.d.ts | 28 +++++++ .../src/client/preview/angular/app.token.ts | 4 +- .../src/client/preview/angular/helpers.ts | 81 ++++++++++++------- 4 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 app/angular/demo.d.ts create mode 100644 app/angular/index.d.ts diff --git a/app/angular/demo.d.ts b/app/angular/demo.d.ts new file mode 100644 index 000000000000..7ff09737fcd0 --- /dev/null +++ b/app/angular/demo.d.ts @@ -0,0 +1,4 @@ +declare module '@storybook/angular/demo' { + export const Button: any; + export const Welcome: any; +} \ No newline at end of file diff --git a/app/angular/index.d.ts b/app/angular/index.d.ts new file mode 100644 index 000000000000..26aae28f83a3 --- /dev/null +++ b/app/angular/index.d.ts @@ -0,0 +1,28 @@ +export interface IStorybookStory { + name: string, + render: () => any +} + +export interface IStoribookSection { + kind: string, + stories: IStorybookStory[] +} + +export type IGetStory = () => { + props?: {[p: string]: any}; + component: any +}; + +export interface IApi { + kind: string; + addDecorator: (decorator: any) => IApi; + add: (storyName: string, getStory: IGetStory ) => IApi; +} + +declare module '@storybook/angular' { + export function storiesOf(kind: string, module: NodeModule): IApi; + export function setAddon(addon: any): void; + export function addDecorator(decorator: any): IApi; + export function configure(loaders: () => NodeRequire, module: NodeModule): void; + export function getStorybook(): IStoribookSection[]; +} diff --git a/app/angular/src/client/preview/angular/app.token.ts b/app/angular/src/client/preview/angular/app.token.ts index 278844d0a449..75906828d014 100644 --- a/app/angular/src/client/preview/angular/app.token.ts +++ b/app/angular/src/client/preview/angular/app.token.ts @@ -4,6 +4,6 @@ export const STORY = new InjectionToken("story"); export type Data = { component: any; - props: object; - propsMeta: object; + props: {[p: string]: any}; + propsMeta: {[p: string]: any}; } \ No newline at end of file diff --git a/app/angular/src/client/preview/angular/helpers.ts b/app/angular/src/client/preview/angular/helpers.ts index b33ad7285ea0..72340d8f29b0 100644 --- a/app/angular/src/client/preview/angular/helpers.ts +++ b/app/angular/src/client/preview/angular/helpers.ts @@ -1,4 +1,6 @@ import { + Type, + PlatformRef, enableProdMode, NgModule, Component, @@ -11,29 +13,48 @@ import { BrowserModule } from "@angular/platform-browser"; import { AppComponent } from "./components/app.component"; import { ErrorComponent } from "./components/error.component"; import { NoPreviewComponent } from "./components/no-preview.component"; -import { STORY } from "./app.token"; -let platform = null; -let promises = []; +import { STORY, Data } from "./app.token"; + +let platform: PlatformRef = null; +let promises: Promise>[] = []; + +export interface IContext { + [p: string]: any +}; +export type IGetStoryWithContext = (context: IContext) => Data +type IRenderStoryFn = (story: IGetStoryWithContext, context: IContext, reRender?: boolean) => void; +type IRenderErrorFn = (error: Error) => void; + +interface IModule extends Type { + annotations: any[]; +} +interface IComponent extends Type { + annotations: any[]; + parameters: any[]; + propsMetadata: any[] + +} // Taken from https://davidwalsh.name/javascript-debounce-function // We don't want to pull underscore - -const debounce = (func, wait = 100, immediate = false) => { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; +const debounce = (func: IRenderStoryFn | IRenderErrorFn, + wait: number = 100, + immediate: boolean = false): () => void => { + var timeout: number; + return function () { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; }; -const getComponentMetadata = ({ component, props = {}, propsMeta = {} }) => { +const getComponentMetadata = ({component, props = {}, propsMeta = {}}: Data) => { if (!component || typeof component !== "function") throw new Error("No valid component provided"); @@ -56,8 +77,11 @@ const getComponentMetadata = ({ component, props = {}, propsMeta = {} }) => { }; }; -const getAnnotatedComponent = (meta, component, propsMeta, params) => { - const NewComponent: any = function NewComponent(...args) { +const getAnnotatedComponent = (meta: NgModule, + component: any, + propsMeta: { [p: string]: any }, + params: any[]): IComponent => { + const NewComponent: any = function NewComponent(...args: any[]) { component.call(this, ...args); }; NewComponent.prototype = Object.create(component.prototype); @@ -67,7 +91,10 @@ const getAnnotatedComponent = (meta, component, propsMeta, params) => { return NewComponent; }; -const getModule = (declarations, entryComponents, bootstrap, data) => { +const getModule = (declarations: Array | any[]>, + entryComponents: Array | any[]>, + bootstrap: Array | any[]>, + data: Data): IModule => { const moduleMeta = new NgModule({ declarations: [...declarations], imports: [BrowserModule], @@ -78,12 +105,12 @@ const getModule = (declarations, entryComponents, bootstrap, data) => { }); const NewModule: any = function NewModule() {}; - NewModule.annotations = [moduleMeta]; + (NewModule).annotations = [moduleMeta]; return NewModule; }; -const initModule = (currentStory, context, reRender) => { +const initModule = (currentStory: IGetStoryWithContext, context: IContext, reRender: boolean): IModule => { const { component, componentMeta, @@ -115,7 +142,7 @@ const initModule = (currentStory, context, reRender) => { return Module; }; -const draw = (newModule, reRender = true) => { +const draw = (newModule: IModule, reRender: boolean = true): void => { if (!platform) { try { enableProdMode(); @@ -137,9 +164,9 @@ const draw = (newModule, reRender = true) => { } }; -export const renderNgError = debounce((error) => { +export const renderNgError = debounce((error: Error) => { const errorData = { - component: null, + component: null, props: { message: error.message, stack: error.stack @@ -157,7 +184,7 @@ export const renderNoPreview = debounce(() => { [NoPreviewComponent], [], [NoPreviewComponent], - {} + {} ); draw(Module); From ce8544af9c1b328eb32b0c551ec7e291c531560b Mon Sep 17 00:00:00 2001 From: ralzinov Date: Wed, 13 Dec 2017 19:40:29 +0300 Subject: [PATCH 2/4] fix typing errors in tests --- app/angular/src/client/preview/angular/helpers.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/angular/src/client/preview/angular/helpers.ts b/app/angular/src/client/preview/angular/helpers.ts index 72340d8f29b0..662afb5c70ce 100644 --- a/app/angular/src/client/preview/angular/helpers.ts +++ b/app/angular/src/client/preview/angular/helpers.ts @@ -1,11 +1,9 @@ import { Type, - PlatformRef, enableProdMode, NgModule, Component, NgModuleRef, - ApplicationRef, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core"; import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; @@ -15,12 +13,13 @@ import { ErrorComponent } from "./components/error.component"; import { NoPreviewComponent } from "./components/no-preview.component"; import { STORY, Data } from "./app.token"; -let platform: PlatformRef = null; +let platform: any = null; let promises: Promise>[] = []; export interface IContext { [p: string]: any -}; +} + export type IGetStoryWithContext = (context: IContext) => Data type IRenderStoryFn = (story: IGetStoryWithContext, context: IContext, reRender?: boolean) => void; type IRenderErrorFn = (error: Error) => void; @@ -40,7 +39,7 @@ interface IComponent extends Type { const debounce = (func: IRenderStoryFn | IRenderErrorFn, wait: number = 100, immediate: boolean = false): () => void => { - var timeout: number; + var timeout: any; return function () { var context = this, args = arguments; var later = function() { From e00356183d8600be2246e8745840d059503645fb Mon Sep 17 00:00:00 2001 From: ralzinov Date: Fri, 22 Dec 2017 13:34:14 +0300 Subject: [PATCH 3/4] fixed conflicts, added annotation to merged files --- .../src/client/preview/angular/helpers.ts | 24 +++++++------------ .../src/client/preview/angular/types.ts | 12 +++++++--- .../src/client/preview/angular/utils.ts | 10 ++++---- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/app/angular/src/client/preview/angular/helpers.ts b/app/angular/src/client/preview/angular/helpers.ts index 41ad2f1665d3..cfbb3f7639fd 100644 --- a/app/angular/src/client/preview/angular/helpers.ts +++ b/app/angular/src/client/preview/angular/helpers.ts @@ -11,18 +11,13 @@ import { BrowserModule } from "@angular/platform-browser"; import { AppComponent } from "./components/app.component"; import { ErrorComponent } from "./components/error.component"; import { NoPreviewComponent } from "./components/no-preview.component"; -import { STORY, Data } from "./app.token"; +import { STORY } from "./app.token"; import { getAnnotations, getParameters, getPropMetadata } from './utils'; -import { NgModuleMetadata, NgStory, NgError, NgProvidedData } from "./types"; +import { NgModuleMetadata, NgStory, IGetStoryWithContext, IContext, NgProvidedData } from "./types"; let platform: any = null; let promises: Promise>[] = []; -export interface IContext { - [p: string]: any -} - -export type IGetStoryWithContext = (context: IContext) => Data type IRenderStoryFn = (story: IGetStoryWithContext, context: IContext, reRender?: boolean) => void; type IRenderErrorFn = (error: Error) => void; @@ -33,7 +28,6 @@ interface IComponent extends Type { annotations: any[]; parameters: any[]; propsMetadata: any[] - } // Taken from https://davidwalsh.name/javascript-debounce-function @@ -41,14 +35,14 @@ interface IComponent extends Type { const debounce = (func: IRenderStoryFn | IRenderErrorFn, wait: number = 100, immediate: boolean = false): () => void => { - var timeout; + let timeout: any; return function () { - var context = this, args = arguments; - var later = function () { + let context = this, args = arguments; + let later = function () { timeout = null; if (!immediate) func.apply(context, args); }; - var callNow = immediate && !timeout; + let callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); @@ -71,7 +65,7 @@ const getComponentMetadata = ( const paramsMetadata = getParameters(component); Object.keys(propsMeta).map(key => { - propsMetadata[key] = propsMeta[key]; + (propsMetadata)[key] = (propsMeta)[key]; }); const { @@ -161,15 +155,13 @@ const initModule = (currentStory: IGetStoryWithContext, context: IContext, reRen propsMeta }; - const Module = getModule( + return getModule( [AppComponent, AnnotatedComponent], [AnnotatedComponent], [AppComponent], story, moduleMeta ); - - return Module; }; const draw = (newModule: IModule, reRender: boolean = true): void => { diff --git a/app/angular/src/client/preview/angular/types.ts b/app/angular/src/client/preview/angular/types.ts index 22d4bb89b454..9302e85de66f 100644 --- a/app/angular/src/client/preview/angular/types.ts +++ b/app/angular/src/client/preview/angular/types.ts @@ -7,8 +7,8 @@ export interface NgModuleMetadata { export interface NgStory { component: any, - props: object, - propsMeta: object, + props: {[p: string]: any}, + propsMeta: {[p: string]: any}, moduleMetadata?: NgModuleMetadata } @@ -17,4 +17,10 @@ export interface NgError { stack: string } -export type NgProvidedData = NgStory | NgError; \ No newline at end of file +export type NgProvidedData = NgStory | NgError; + +export interface IContext { + [p: string]: any +} + +export type IGetStoryWithContext = (context: IContext) => NgStory \ No newline at end of file diff --git a/app/angular/src/client/preview/angular/utils.ts b/app/angular/src/client/preview/angular/utils.ts index 843aa5ac4df4..1ec935cd6e9a 100644 --- a/app/angular/src/client/preview/angular/utils.ts +++ b/app/angular/src/client/preview/angular/utils.ts @@ -1,4 +1,4 @@ -function getMeta(component, [name1, name2]: any, defaultValue) { +function getMeta(component: any, [name1, name2]: any, defaultValue: any) { if (!name2) { name2 = name1; name1 = `__${name1}__`; @@ -12,17 +12,17 @@ function getMeta(component, [name1, name2]: any, defaultValue) { return component[name2]; } - return window['Reflect'].getMetadata(name2, component) || defaultValue; + return (window)['Reflect'].getMetadata(name2, component) || defaultValue; } -export function getAnnotations(component) { +export function getAnnotations(component: any) { return getMeta(component, ['annotations'], []); } -export function getPropMetadata(component) { +export function getPropMetadata(component: any) { return getMeta(component, ['__prop__metadata__', 'propMetadata'], {}); } -export function getParameters(component) { +export function getParameters(component: any) { return getMeta(component, ['parameters'], []); } \ No newline at end of file From 0df588b216ffb10743e48a8b557c2931dbb3e930 Mon Sep 17 00:00:00 2001 From: ralzinov Date: Fri, 22 Dec 2017 20:58:43 +0300 Subject: [PATCH 4/4] added "moduleMetadata" property to IGetStory interface at index.d.ts --- app/angular/index.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/angular/index.d.ts b/app/angular/index.d.ts index 26aae28f83a3..1cbe7beb3bdb 100644 --- a/app/angular/index.d.ts +++ b/app/angular/index.d.ts @@ -1,3 +1,5 @@ +import {NgModuleMetadata } from './dist/client/preview/angular/types'; + export interface IStorybookStory { name: string, render: () => any @@ -10,6 +12,7 @@ export interface IStoribookSection { export type IGetStory = () => { props?: {[p: string]: any}; + moduleMetadata?: {[p: string]: NgModuleMetadata}; component: any };