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

Added type annotation to helpers, added ts declaration files for angu… #2459

Merged
merged 17 commits into from
Dec 22, 2017
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: 4 additions & 0 deletions app/angular/demo.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module '@storybook/angular/demo' {
export const Button: any;
export const Welcome: any;
}
31 changes: 31 additions & 0 deletions app/angular/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {NgModuleMetadata } from './dist/client/preview/angular/types';

export interface IStorybookStory {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also have type definitions in the @types/... npm organisation.

Should we move these here? Or add them there also?
Are these even the same type of definitions?

👍

Copy link
Contributor Author

@ralzinov ralzinov Dec 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any typings for apps at https://microsoft.github.io/TypeSearch/, only for addons.
I think app and type definitioins for it should be in same package, at least written with typescript like angular. It's not the same typings.

name: string,
render: () => any
}

export interface IStoribookSection {
kind: string,
stories: IStorybookStory[]
}

export type IGetStory = () => {
props?: {[p: string]: any};
moduleMetadata?: {[p: string]: NgModuleMetadata};
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[];
}
66 changes: 42 additions & 24 deletions app/angular/src/client/preview/angular/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {
Type,
enableProdMode,
NgModule,
Component
Component,
NgModuleRef
} from "@angular/core";

import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
Expand All @@ -11,23 +13,36 @@ import { ErrorComponent } from "./components/error.component";
import { NoPreviewComponent } from "./components/no-preview.component";
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 = null;
let promises = [];
let platform: any = null;
let promises: Promise<NgModuleRef<any>>[] = [];

type IRenderStoryFn = (story: IGetStoryWithContext, context: IContext, reRender?: boolean) => void;
type IRenderErrorFn = (error: Error) => void;

interface IModule extends Type<any> {
annotations: any[];
}
interface IComponent extends Type<any> {
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;
const debounce = (func: IRenderStoryFn | IRenderErrorFn,
wait: number = 100,
immediate: boolean = false): () => void => {
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);
Expand All @@ -50,7 +65,7 @@ const getComponentMetadata = (
const paramsMetadata = getParameters(component);

Object.keys(propsMeta).map(key => {
propsMetadata[key] = propsMeta[key];
(<any>propsMetadata)[key] = (<any>propsMeta)[key];
});

const {
Expand All @@ -75,8 +90,11 @@ const getComponentMetadata = (
};
};

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);
};

Expand All @@ -88,12 +106,16 @@ const getAnnotatedComponent = (meta, component, propsMeta, params) => {
return NewComponent;
};

const getModule = (declarations, entryComponents, bootstrap, data: NgProvidedData, moduleMetadata: NgModuleMetadata = {
const getModule = (declarations: Array<Type<any> | any[]>,
entryComponents: Array<Type<any> | any[]>,
bootstrap: Array<Type<any> | any[]>,
data: NgProvidedData,
moduleMetadata: NgModuleMetadata = {
imports: [],
schemas: [],
declarations: [],
providers: []
}) => {
}): IModule => {
const moduleMeta = new NgModule({
declarations: [...declarations, ...moduleMetadata.declarations],
imports: [BrowserModule, ...moduleMetadata.imports],
Expand All @@ -104,13 +126,11 @@ const getModule = (declarations, entryComponents, bootstrap, data: NgProvidedDat
});

const NewModule: any = function NewModule() {};

NewModule.annotations = [moduleMeta];

(<IModule>NewModule).annotations = [moduleMeta];
return NewModule;
};

const initModule = (currentStory, context, reRender) => {
const initModule = (currentStory: IGetStoryWithContext, context: IContext, reRender: boolean): IModule => {
const {
component,
componentMeta,
Expand All @@ -135,18 +155,16 @@ const initModule = (currentStory, context, reRender) => {
propsMeta
};

const Module = getModule(
return getModule(
[AppComponent, AnnotatedComponent],
[AnnotatedComponent],
[AppComponent],
story,
moduleMeta
);

return Module;
};

const draw = (newModule, reRender = true) => {
const draw = (newModule: IModule, reRender: boolean = true): void => {
if (!platform) {
try {
enableProdMode();
Expand All @@ -168,7 +186,7 @@ const draw = (newModule, reRender = true) => {
}
};

export const renderNgError = debounce((error) => {
export const renderNgError = debounce((error: Error) => {
const errorData = {
message: error.message,
stack: error.stack
Expand Down
12 changes: 9 additions & 3 deletions app/angular/src/client/preview/angular/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -17,4 +17,10 @@ export interface NgError {
stack: string
}

export type NgProvidedData = NgStory | NgError;
export type NgProvidedData = NgStory | NgError;

export interface IContext {
[p: string]: any
}

export type IGetStoryWithContext = (context: IContext) => NgStory
10 changes: 5 additions & 5 deletions app/angular/src/client/preview/angular/utils.ts
Original file line number Diff line number Diff line change
@@ -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}__`;
Expand All @@ -12,17 +12,17 @@ function getMeta(component, [name1, name2]: any, defaultValue) {
return component[name2];
}

return window['Reflect'].getMetadata(name2, component) || defaultValue;
return (<any>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'], []);
}