Skip to content

Commit

Permalink
refactor(headless): combined SSR *WithProps and *WithoutProps interfa…
Browse files Browse the repository at this point in the history
  • Loading branch information
btaillon-coveo authored Oct 6, 2023
1 parent 0bd390f commit 74ad0cc
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 226 deletions.
104 changes: 49 additions & 55 deletions packages/headless/src/app/search-engine/search-engine.ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
import {AnyAction} from '@reduxjs/toolkit';
import {Controller} from '../../controllers';
import {createWaitForActionMiddleware} from '../../utils/utils';
import {EngineDefinitionBuildOptionsWithProps} from '../ssr-engine/types/build';
import {
ControllerDefinitionsMap,
EngineStaticState,
InferControllerPropsMapFromDefinitions,
InferControllerStaticStateMapFromDefinitions,
OptionsExtender,
} from '../ssr-engine/types/common';
import {
Expand Down Expand Up @@ -67,11 +64,15 @@ export function defineSearchEngine<
controllers: controllerDefinitions,
...engineOptions
}: SearchEngineDefinitionOptions<TControllerDefinitions>): SearchEngineDefinition<TControllerDefinitions> {
const build: SearchEngineDefinition<TControllerDefinitions>['build'] = async (
...[buildOptions]: Parameters<
SearchEngineDefinition<TControllerDefinitions>['build']
>
) => {
type Definition = SearchEngineDefinition<TControllerDefinitions>;
type BuildFunction = Definition['build'];
type FetchStaticStateFunction = Definition['fetchStaticState'];
type HydrateStaticStateFunction = Definition['hydrateStaticState'];
type BuildParameters = Parameters<BuildFunction>;
type FetchStaticStateParameters = Parameters<FetchStaticStateFunction>;
type HydrateStaticStateParameters = Parameters<HydrateStaticStateFunction>;

const build: BuildFunction = async (...[buildOptions]: BuildParameters) => {
const engine = buildSearchEngine(
buildOptions?.extend
? await buildOptions.extend(engineOptions)
Expand All @@ -90,57 +91,50 @@ export function defineSearchEngine<
};
};

const fetchStaticState: SearchEngineDefinition<TControllerDefinitions>['fetchStaticState'] =
async (
...[executeOptions]: Parameters<
SearchEngineDefinition<TControllerDefinitions>['fetchStaticState']
>
): Promise<
EngineStaticState<
{type: string},
InferControllerStaticStateMapFromDefinitions<TControllerDefinitions>
>
> => {
const {middleware, promise: searchCompletedPromise} =
createWaitForActionMiddleware(isSearchCompletedAction);
const fetchStaticState: FetchStaticStateFunction = async (
...[fetchOptions]: FetchStaticStateParameters
) => {
const {middleware, promise: searchCompletedPromise} =
createWaitForActionMiddleware(isSearchCompletedAction);

const extend: OptionsExtender<SearchEngineOptions> = (options) => ({
...options,
middlewares: [...(options.middlewares ?? []), middleware],
});
const {engine, controllers} = await build({
extend,
...(executeOptions?.controllers && {
controllers: executeOptions.controllers,
}),
});
const extend: OptionsExtender<SearchEngineOptions> = (options) => ({
...options,
middlewares: [...(options.middlewares ?? []), middleware],
});
const {engine, controllers} = await build(
...([
{
extend,
...(fetchOptions &&
'controllers' in fetchOptions && {
controllers: fetchOptions.controllers,
}),
},
] as BuildParameters)
);

engine.executeFirstSearch();
return createStaticState({
searchAction: await searchCompletedPromise,
controllers,
});
};
engine.executeFirstSearch();
return createStaticState({
searchAction: await searchCompletedPromise,
controllers,
});
};

const hydrateStaticState: SearchEngineDefinition<TControllerDefinitions>['hydrateStaticState'] =
async (
...[hydrateOptions]: Parameters<
SearchEngineDefinition<TControllerDefinitions>['hydrateStaticState']
>
) => {
const {engine, controllers} = await build(
'controllers' in hydrateOptions
? ({
const hydrateStaticState: HydrateStaticStateFunction = async (
...[hydrateOptions]: HydrateStaticStateParameters
) => {
const {engine, controllers} = await build(
...(('controllers' in hydrateOptions!
? [
{
controllers: hydrateOptions.controllers,
} as EngineDefinitionBuildOptionsWithProps<
SearchEngineOptions,
TControllerDefinitions
>)
: {}
);
engine.dispatch(hydrateOptions.searchAction);
return {engine, controllers};
};
},
]
: []) as BuildParameters)
);
engine.dispatch(hydrateOptions!.searchAction);
return {engine, controllers};
};

return {
build,
Expand Down
38 changes: 10 additions & 28 deletions packages/headless/src/app/ssr-engine/types/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,17 @@ import {CoreEngine} from '../../engine';
import {
ControllersMap,
ControllersPropsMap,
HydratedState,
EngineDefinitionBuildResult,
EngineDefinitionControllersPropsOption,
OptionsExtender,
OptionsTuple,
} from './common';

export interface EngineDefinitionBuildOptionsWithoutProps<TEngineOptions> {
export interface BuildOptions<TEngineOptions> {
extend?: OptionsExtender<TEngineOptions>;
}

export interface EngineDefinitionBuildOptionsWithProps<
TEngineOptions,
TControllersProps extends ControllersPropsMap,
> extends EngineDefinitionBuildOptionsWithoutProps<TEngineOptions> {
controllers: TControllersProps;
}

export interface BuildWithProps<
export interface Build<
TEngine extends CoreEngine,
TEngineOptions,
TControllersMap extends ControllersMap,
Expand All @@ -26,23 +21,10 @@ export interface BuildWithProps<
/**
* Initializes an engine and controllers from the definition.
*/
build(
options: EngineDefinitionBuildOptionsWithProps<
TEngineOptions,
TControllersProps
(
...params: OptionsTuple<
BuildOptions<TEngineOptions> &
EngineDefinitionControllersPropsOption<TControllersProps>
>
): Promise<HydratedState<TEngine, TControllersMap>>;
}

export interface BuildWithoutProps<
TEngine extends CoreEngine,
TEngineOptions,
TControllersMap extends ControllersMap,
> {
/**
* Initializes an engine and controllers from the definition.
*/
build(
options?: EngineDefinitionBuildOptionsWithoutProps<TEngineOptions>
): Promise<HydratedState<TEngine, TControllersMap>>;
): Promise<EngineDefinitionBuildResult<TEngine, TControllersMap>>;
}
35 changes: 31 additions & 4 deletions packages/headless/src/app/ssr-engine/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ export type HasKeys<TObject> = TObject extends {}
: true
: boolean;

export type ExtractRequiredOptions<TOptions> = {
[TKey in keyof TOptions as Pick<TOptions, TKey> extends Required<
Pick<TOptions, TKey>
>
? TKey
: never]: TOptions[TKey];
};

export type OptionsTuple<TOptions> = HasKeys<TOptions> extends false
? []
: HasKeys<ExtractRequiredOptions<TOptions>> extends false
? [options?: TOptions]
: [options: TOptions];

export interface OptionsExtender<TOptions> {
(options: TOptions): TOptions | Promise<TOptions>;
}
Expand Down Expand Up @@ -68,6 +82,14 @@ export interface ControllerDefinitionsMap<
[customName: string]: ControllerDefinition<TEngine, TController>;
}

export interface EngineDefinitionBuildResult<
TEngine extends CoreEngine,
TControllers extends ControllersMap,
> {
engine: TEngine;
controllers: TControllers;
}

export interface EngineStaticState<
TSearchAction extends AnyAction,
TControllers extends ControllerStaticStateMap,
Expand All @@ -79,10 +101,7 @@ export interface EngineStaticState<
export interface HydratedState<
TEngine extends CoreEngine,
TControllers extends ControllersMap,
> {
engine: TEngine;
controllers: TControllers;
}
> extends EngineDefinitionBuildResult<TEngine, TControllers> {}

export type InferControllerPropsFromDefinition<
TController extends ControllerDefinition<CoreEngine, Controller>,
Expand Down Expand Up @@ -141,3 +160,11 @@ export type InferControllerStaticStateMapFromControllers<
TControllers[K]
>;
};

export type EngineDefinitionControllersPropsOption<
TControllersPropsMap extends ControllersPropsMap,
> = HasKeys<TControllersPropsMap> extends false
? {}
: {
controllers: TControllersPropsMap;
};
118 changes: 30 additions & 88 deletions packages/headless/src/app/ssr-engine/types/core-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,15 @@ import {AnyAction} from '@reduxjs/toolkit';
import {Controller} from '../../../controllers';
import {CoreEngine} from '../../engine';
import {EngineConfiguration} from '../../engine-configuration';
import {BuildWithProps, BuildWithoutProps} from './build';
import {Build} from './build';
import {
ControllerDefinitionsMap,
ControllersPropsMap,
HasKeys,
InferControllerPropsMapFromDefinitions,
InferControllerStaticStateMapFromDefinitions,
InferControllersMapFromDefinition,
ControllerStaticStateMap,
ControllersMap,
} from './common';
import {
FetchStaticStateWithProps,
FetchStaticStateWithoutProps,
} from './fetch-static-state';
import {
HydrateStaticStateWithProps,
HydrateStaticStateWithoutProps,
} from './hydrate-static-state';
import {FetchStaticState} from './fetch-static-state';
import {HydrateStaticState} from './hydrate-static-state';

export type EngineDefinitionOptions<
TOptions extends {configuration: EngineConfiguration},
Expand All @@ -32,92 +22,44 @@ export type EngineDefinitionOptions<
controllers?: TControllers;
};

export type EngineDefinition<
TEngine extends CoreEngine,
TControllers extends ControllerDefinitionsMap<TEngine, Controller>,
TEngineOptions,
> = HasKeys<InferControllerPropsMapFromDefinitions<TControllers>> extends true
? EngineDefinitionWithProps<
TEngine,
TControllers,
TEngineOptions,
InferControllerPropsMapFromDefinitions<TControllers>
>
: HasKeys<InferControllerPropsMapFromDefinitions<TControllers>> extends false
? EngineDefinitionWithoutProps<TEngine, TControllers, TEngineOptions>
:
| EngineDefinitionWithProps<
TEngine,
TControllers,
TEngineOptions,
ControllersPropsMap
>
| EngineDefinitionWithoutProps<TEngine, TControllers, TEngineOptions>;

export interface EngineDefinitionWithoutProps<
export interface EngineDefinition<
TEngine extends CoreEngine,
TControllers extends ControllerDefinitionsMap<TEngine, Controller>,
TEngineOptions,
> extends FetchStaticStateWithoutProps<
InferControllerStaticStateMapFromDefinitions<TControllers>,
AnyAction
>,
HydrateStaticStateWithoutProps<
TEngine,
InferControllersMapFromDefinition<TControllers>,
AnyAction
>,
BuildWithoutProps<
TEngine,
TEngineOptions,
InferControllersMapFromDefinition<TControllers>
> {}

export interface EngineDefinitionWithProps<
TEngine extends CoreEngine,
TControllers extends ControllerDefinitionsMap<TEngine, Controller>,
TEngineOptions,
TControllerProps extends ControllersPropsMap,
> extends FetchStaticStateWithProps<
InferControllerStaticStateMapFromDefinitions<TControllers>,
AnyAction,
TControllerProps
>,
HydrateStaticStateWithProps<
TEngine,
InferControllersMapFromDefinition<TControllers>,
AnyAction,
TControllerProps
>,
BuildWithProps<
TEngine,
TEngineOptions,
InferControllersMapFromDefinition<TControllers>,
TControllerProps
> {}
> {
fetchStaticState: FetchStaticState<
InferControllerStaticStateMapFromDefinitions<TControllers>,
AnyAction,
InferControllerPropsMapFromDefinitions<TControllers>
>;
hydrateStaticState: HydrateStaticState<
TEngine,
InferControllersMapFromDefinition<TControllers>,
AnyAction,
InferControllerPropsMapFromDefinitions<TControllers>
>;
build: Build<
TEngine,
TEngineOptions,
InferControllersMapFromDefinition<TControllers>,
InferControllerPropsMapFromDefinitions<TControllers>
>;
}

/**
* @internal
*/
export type InferStaticState<
T extends
| FetchStaticStateWithoutProps<ControllerStaticStateMap, AnyAction>
| FetchStaticStateWithProps<
ControllerStaticStateMap,
AnyAction,
ControllersPropsMap
>,
T extends {
fetchStaticState(...args: unknown[]): Promise<unknown>;
},
> = Awaited<ReturnType<T['fetchStaticState']>>;

/**
* @internal
*/
export type InferHydratedState<
T extends
| HydrateStaticStateWithoutProps<CoreEngine, ControllersMap, AnyAction>
| HydrateStaticStateWithProps<
CoreEngine,
ControllersMap,
AnyAction,
ControllersPropsMap
>,
T extends {
hydrateStaticState(...args: unknown[]): Promise<unknown>;
},
> = Awaited<ReturnType<T['hydrateStaticState']>>;
Loading

0 comments on commit 74ad0cc

Please sign in to comment.