Skip to content

Commit

Permalink
chore: migrate manager-api to strict ts
Browse files Browse the repository at this point in the history
Co-authored-by: LuisChiej <[email protected]>
  • Loading branch information
gitstart and LuisChiej committed Sep 21, 2023
1 parent 1a0d84f commit 64d12f0
Show file tree
Hide file tree
Showing 20 changed files with 423 additions and 269 deletions.
29 changes: 18 additions & 11 deletions code/lib/manager-api/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export { default as merge } from './lib/merge';
export type { Options as StoreOptions, Listener as ChannelListener };
export { ActiveTabs };

export const ManagerContext = createContext({ api: undefined, state: getInitialState({}) });
export const ManagerContext = createContext({ api: {} as API, state: getInitialState({}) });

export type State = layout.SubState &
stories.SubState &
Expand Down Expand Up @@ -200,7 +200,10 @@ class ManagerProvider extends Component<ManagerProviderProps, State> {
);

// Create our initial state by combining the initial state of all modules, then overlaying any saved state
const state = getInitialState(this.state, ...this.modules.map((m) => m.state));
const state = getInitialState(
this.state,
this.modules.map((m) => m.state as State)
);

// Get our API by combining the APIs exported by each module
const api: API = Object.assign(this.api, { navigate }, ...this.modules.map((m) => m.api));
Expand All @@ -209,7 +212,9 @@ class ManagerProvider extends Component<ManagerProviderProps, State> {
this.api = api;
}

static getDerivedStateFromProps(props: ManagerProviderProps, state: State): State {
static getDerivedStateFromProps(props: ManagerProviderProps, state: State): State | null {
if (!props.storyId) throw new Error('StoryId cannot be undefined');

if (state.path !== props.path) {
return {
...state,
Expand Down Expand Up @@ -241,7 +246,7 @@ class ManagerProvider extends Component<ManagerProviderProps, State> {
// a chance to do things that call other modules' APIs.
this.modules.forEach((module) => {
if ('init' in module) {
module.init();
module.init?.();
}
});
};
Expand Down Expand Up @@ -283,7 +288,7 @@ interface ManagerConsumerProps<P = unknown> {

const defaultFilter = (c: Combo) => c;

function ManagerConsumer<P = Combo>({
function ManagerConsumer<P extends object = Combo>({
// @ts-expect-error (Converted from ts-ignore)
filter = defaultFilter,
children,
Expand All @@ -299,7 +304,9 @@ function ManagerConsumer<P = Combo>({
const data = filterer.current(c);

const l = useMemo(() => {
return [...Object.entries(data).reduce((acc, keyval) => acc.concat(keyval), [])];
return [
...Object.entries(data as object).reduce<unknown[]>((acc, keyval) => acc.concat(keyval), []),
];
}, [c.state]);

return useMemo(() => {
Expand Down Expand Up @@ -375,14 +382,14 @@ export const useChannel = (eventMap: API_EventMap, deps: any[] = []) => {

export function useStoryPrepared(storyId?: StoryId) {
const api = useStorybookApi();
return api.isPrepared(storyId);
return storyId ? api.isPrepared(storyId) : undefined;
}

export function useParameter<S>(parameterKey: string, defaultValue?: S) {
export function useParameter<S>(parameterKey: string, defaultValue: S) {
const api = useStorybookApi();

const result = api.getCurrentParameter<S>(parameterKey);
return orDefault<S>(result, defaultValue);
return orDefault<S>(result, defaultValue as S);
}

// cache for taking care of HMR
Expand Down Expand Up @@ -472,7 +479,7 @@ export function useArgs(): [Args, (newArgs: Args) => void, (argNames?: string[])
const { getCurrentStoryData, updateStoryArgs, resetStoryArgs } = useStorybookApi();

const data = getCurrentStoryData();
const args = data?.type === 'story' ? data.args : {};
const args = data?.type === 'story' ? data.args ?? {} : {};
const updateArgs = useCallback(
(newArgs: Args) => updateStoryArgs(data as API_StoryEntry, newArgs),
[data, updateStoryArgs]
Expand All @@ -494,7 +501,7 @@ export function useGlobalTypes(): ArgTypes {
return useStorybookApi().getGlobalTypes();
}

function useCurrentStory(): API_StoryEntry | API_DocsEntry {
function useCurrentStory(): API_StoryEntry | API_DocsEntry | undefined {
const { getCurrentStoryData } = useStorybookApi();

return getCurrentStoryData();
Expand Down
6 changes: 5 additions & 1 deletion code/lib/manager-api/src/lib/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ export class AddonStore {
getChannel = (): Channel => {
// this.channel should get overwritten by setChannel. If it wasn't called (e.g. in non-browser environment), set a mock instead.
if (!this.channel) {
this.setChannel(mockChannel());
const nextChannel = mockChannel();

this.setChannel(nextChannel);

return nextChannel;
}

return this.channel;
Expand Down
2 changes: 1 addition & 1 deletion code/lib/manager-api/src/lib/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { API_ComposedRef } from '@storybook/types';
import { getSourceType } from '../modules/refs';
import type { API } from '../index';

interface Meta {
export interface Meta {
ref?: API_ComposedRef;
source?: string;
sourceType?: 'local' | 'external';
Expand Down
6 changes: 5 additions & 1 deletion code/lib/manager-api/src/lib/shortcut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ export const eventMatchesShortcut = (
e: KeyboardEventLike,
shortcut: API_KeyCollection
): boolean => {
return shortcutMatchesShortcut(eventToShortcut(e), shortcut);
const inputShortcut = eventToShortcut(e);

if (inputShortcut === null) return false;

return shortcutMatchesShortcut(inputShortcut, shortcut);
};

export const keyToSymbol = (key: string): string => {
Expand Down
23 changes: 15 additions & 8 deletions code/lib/manager-api/src/lib/store-setup.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
/* eslint-disable no-underscore-dangle */
/* eslint-disable func-names */
import type { DeveloperTools } from 'store2';
import { parse, stringify } from 'telejson';

// setting up the store, overriding set and get to use telejson
export default (_: any) => {
_.fn('set', function (key: string, data: object) {
return _.set(this._area, this._in(key), stringify(data, { maxDepth: 50 }));
});
_.fn('get', function (key: string, alt: string) {
const value = _.get(this._area, this._in(key));
return value !== null ? parse(value) : alt || value;
});
export default (_: DeveloperTools) => {
_.fn(
'set',
function (this: { _area: Storage; _in: (key: string) => string }, key: string, data: object) {
return _.set(this._area, this._in(key), stringify(data, { maxDepth: 50 }));
}
);
_.fn(
'get',
function (this: { _area: Storage; _in: (key: string) => string }, key: string, alt: string) {
const value = _.get(this._area, this._in(key));
return value !== null ? parse(value) : alt || value;
}
);
};
105 changes: 57 additions & 48 deletions code/lib/manager-api/src/lib/stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
API_HashEntry,
SetStoriesPayload,
StoryIndexV2,
API_PreparedIndexEntry,
} from '@storybook/types';
// eslint-disable-next-line import/no-cycle
import { type API, combineParameters, type State } from '../index';
Expand Down Expand Up @@ -121,7 +122,7 @@ export const transformStoryIndexV3toV4 = (index: StoryIndexV3): API_PreparedStor
type,
...(type === 'docs' && { tags: ['stories-mdx'], storiesImports: [] }),
...entry,
};
} as API_PreparedIndexEntry;

// @ts-expect-error (we're removing something that should not be there)
delete acc[entry.id].story;
Expand Down Expand Up @@ -185,7 +186,7 @@ export const transformStoryIndexToStoriesHash = (
// Now create a "path" or sub id for each name
const paths = names.reduce((list, name, idx) => {
const parent = idx > 0 && list[idx - 1];
const id = sanitize(parent ? `${parent}-${name}` : name);
const id = sanitize(parent ? `${parent}-${name}` : `${name}`);

if (parent === id) {
throw new Error(
Expand All @@ -206,21 +207,24 @@ export const transformStoryIndexToStoriesHash = (
const childId = paths[idx + 1] || item.id;

if (root.length && idx === 0) {
acc[id] = merge<API_RootEntry>((acc[id] || {}) as API_RootEntry, {
type: 'root',
id,
name: names[idx],
depth: idx,
renderLabel,
startCollapsed: collapsedRoots.includes(id),
// Note that this will later get appended to the previous list of children (see below)
children: [childId],

// deprecated fields
isRoot: true,
isComponent: false,
isLeaf: false,
});
acc[id] = merge<API_RootEntry>(
(acc[id] || {}) as API_RootEntry,
{
type: 'root',
id,
name: names[idx],
depth: idx,
renderLabel,
startCollapsed: collapsedRoots.includes(id),
// Note that this will later get appended to the previous list of children (see below)
children: [childId],

// deprecated fields
isRoot: true,
isComponent: false,
isLeaf: false,
} as API_RootEntry
);
// Usually the last path/name pair will be displayed as a component,
// *unless* there are other stories that are more deeply nested under it
//
Expand All @@ -230,43 +234,48 @@ export const transformStoryIndexToStoriesHash = (
//
// In this example the entry for 'atoms-button' would *not* be a component.
} else if ((!acc[id] || acc[id].type === 'component') && idx === paths.length - 1) {
acc[id] = merge<API_ComponentEntry>((acc[id] || {}) as API_ComponentEntry, {
type: 'component',
id,
name: names[idx],
parent: paths[idx - 1],
depth: idx,
renderLabel,
...(childId && {
children: [childId],
}),
// deprecated fields
isRoot: false,
isComponent: true,
isLeaf: false,
});
acc[id] = merge<API_ComponentEntry>(
(acc[id] || {}) as API_ComponentEntry,
{
type: 'component',
id,
name: names[idx],
parent: paths[idx - 1],
depth: idx,
renderLabel,
...(childId && {
children: [childId],
}),
// deprecated fields
isRoot: false,
isComponent: true,
isLeaf: false,
} as API_ComponentEntry
);
} else {
acc[id] = merge<API_GroupEntry>((acc[id] || {}) as API_GroupEntry, {
type: 'group',
id,
name: names[idx],
parent: paths[idx - 1],
depth: idx,
renderLabel,
...(childId && {
children: [childId],
}),
// deprecated fields
isRoot: false,
isComponent: false,
isLeaf: false,
});
acc[id] = merge<API_GroupEntry>(
(acc[id] || {}) as API_GroupEntry,
{
type: 'group',
id,
name: names[idx],
parent: paths[idx - 1],
depth: idx,
renderLabel,
...(childId && {
children: [childId],
}),
// deprecated fields
isRoot: false,
isComponent: false,
isLeaf: false,
} as API_GroupEntry
);
}
});

// Finally add an entry for the docs/story itself
acc[item.id] = {
type: 'story',
...item,
depth: paths.length,
parent: paths[paths.length - 1],
Expand Down
8 changes: 6 additions & 2 deletions code/lib/manager-api/src/modules/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { ModuleFn } from '../lib/types';
import type { Options } from '../store';

export interface SubState {
selectedPanel: string;
selectedPanel: string | undefined;
addons: Record<string, never>;
}

Expand Down Expand Up @@ -51,7 +51,7 @@ export interface SubAPI {
* Returns the id of the currently selected panel.
* @returns {string} - The ID of the currently selected panel.
*/
getSelectedPanel: () => string;
getSelectedPanel: () => string | undefined;
/**
* Sets the currently selected panel via it's ID.
* @param {string} panelName - The ID of the panel to select.
Expand Down Expand Up @@ -85,6 +85,10 @@ export interface SubAPI {
export function ensurePanel(panels: API_Panels, selectedPanel?: string, currentPanel?: string) {
const keys = Object.keys(panels);

if (typeof selectedPanel === 'undefined') {
return currentPanel;
}

if (keys.indexOf(selectedPanel) >= 0) {
return selectedPanel;
}
Expand Down
10 changes: 5 additions & 5 deletions code/lib/manager-api/src/modules/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ export const init: ModuleFn<SubAPI, SubState> = ({ provider }) => {
const api: SubAPI = {
getChannel: () => provider.channel,
on: (type, handler) => {
provider.channel.on(type, handler);
provider.channel?.on(type, handler);

return () => provider.channel.off(type, handler);
return () => provider.channel?.off(type, handler);
},
off: (type, handler) => provider.channel.off(type, handler),
once: (type, handler) => provider.channel.once(type, handler),
off: (type, handler) => provider.channel?.off(type, handler),
once: (type, handler) => provider.channel?.once(type, handler),
emit: (type, data, ...args) => {
if (
data?.options?.target &&
Expand All @@ -73,7 +73,7 @@ export const init: ModuleFn<SubAPI, SubState> = ({ provider }) => {
? `storybook-ref-${data.options.target}`
: 'storybook-preview-iframe';
}
provider.channel.emit(type, data, ...args);
provider.channel?.emit(type, data, ...args);
},
collapseAll: () => {
api.emit(STORIES_COLLAPSE_ALL, {});
Expand Down
Loading

0 comments on commit 64d12f0

Please sign in to comment.