Skip to content

Commit 8f2aad2

Browse files
author
Eunjae Lee
authoredApr 6, 2021
feat(middleware): accept partial methods (#4673)
* fix(middleware): accept partial methods * make public api optional, not the internal one * rename the types * ensure at least one method is given to a middleware * fix lint error
1 parent 27c9c8f commit 8f2aad2

7 files changed

+42
-8
lines changed
 

‎src/lib/InstantSearch.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,12 @@ See ${createDocumentationLink({
269269
*/
270270
public use(...middleware: Middleware[]): this {
271271
const newMiddlewareList = middleware.map(fn => {
272-
const newMiddleware = fn({ instantSearchInstance: this });
272+
const newMiddleware = {
273+
subscribe: noop,
274+
unsubscribe: noop,
275+
onStateChange: noop,
276+
...fn({ instantSearchInstance: this }),
277+
};
273278
this.middleware.push({
274279
creator: fn,
275280
instance: newMiddleware,

‎src/lib/__tests__/InstantSearch-test.js

+14
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,20 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/instantsear
287287
For more information, visit https://www.algolia.com/doc/guides/getting-insights-and-analytics/search-analytics/click-through-and-conversions/how-to/send-click-and-conversion-events-with-instantsearch/js/`
288288
);
289289
});
290+
291+
it('accepts middleware with partial methods', () => {
292+
const search = new InstantSearch({
293+
indexName: 'indexName',
294+
searchClient: createSearchClient(),
295+
});
296+
297+
const subscribe = jest.fn();
298+
search.use(() => ({
299+
subscribe,
300+
}));
301+
search.start();
302+
expect(subscribe).toHaveBeenCalledTimes(1);
303+
});
290304
});
291305

292306
describe('InstantSearch', () => {

‎src/middlewares/createInsightsMiddleware.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
InsightsClient,
33
InsightsClientMethod,
4-
Middleware,
4+
InternalMiddleware,
55
Hit,
66
} from '../types';
77
import { getInsightsAnonymousUserTokenInternal } from '../helpers';
@@ -30,7 +30,9 @@ export type InsightsProps = {
3030
) => void;
3131
};
3232

33-
export type CreateInsightsMiddleware = (props: InsightsProps) => Middleware;
33+
export type CreateInsightsMiddleware = (
34+
props: InsightsProps
35+
) => InternalMiddleware;
3436

3537
export const createInsightsMiddleware: CreateInsightsMiddleware = props => {
3638
const { insightsClient: _insightsClient, insightsInitParams, onEvent } =

‎src/middlewares/createMetadataMiddleware.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { InstantSearch, Middleware, Widget } from '../types';
1+
import { InstantSearch, InternalMiddleware, Widget } from '../types';
22
import { Index } from '../widgets/index/index';
33

44
type WidgetMetaData = {
@@ -80,7 +80,7 @@ export function isMetadataEnabled() {
8080
* - widget name
8181
* - connector name
8282
*/
83-
export function createMetadataMiddleware(): Middleware {
83+
export function createMetadataMiddleware(): InternalMiddleware {
8484
return ({ instantSearchInstance }) => {
8585
const payload: Payload = {
8686
widgets: [],

‎src/middlewares/createRouterMiddleware.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
Router,
55
StateMapping,
66
UiState,
7-
Middleware,
7+
InternalMiddleware,
88
RouteState,
99
} from '../types';
1010
import { isEqual } from '../lib/utils';
@@ -14,7 +14,7 @@ export type RouterProps = {
1414
stateMapping?: StateMapping;
1515
};
1616

17-
export type RoutingManager = (props?: RouterProps) => Middleware;
17+
export type RoutingManager = (props?: RouterProps) => InternalMiddleware;
1818

1919
export const createRouterMiddleware: RoutingManager = (props = {}) => {
2020
const {

‎src/types/middleware.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import InstantSearch from '../lib/InstantSearch';
22
import { UiState } from './widget';
3+
import { AtLeastOne } from './utils';
34

45
export type MiddlewareDefinition = {
56
onStateChange(options: { uiState: UiState }): void;
@@ -11,4 +12,10 @@ export type MiddlewareOptions = {
1112
instantSearchInstance: InstantSearch;
1213
};
1314

14-
export type Middleware = (options: MiddlewareOptions) => MiddlewareDefinition;
15+
export type InternalMiddleware = (
16+
options: MiddlewareOptions
17+
) => MiddlewareDefinition;
18+
19+
export type Middleware = (
20+
options: MiddlewareOptions
21+
) => AtLeastOne<MiddlewareDefinition>;

‎src/types/utils.ts

+6
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,9 @@ export type HighlightedParts = {
22
value: string;
33
isHighlighted: boolean;
44
};
5+
6+
// https://stackoverflow.com/questions/48230773/how-to-create-a-partial-like-that-requires-a-single-property-to-be-set/48244432#48244432
7+
export type AtLeastOne<
8+
TTarget,
9+
TMapped = { [Key in keyof TTarget]: Pick<TTarget, Key> }
10+
> = Partial<TTarget> & TMapped[keyof TMapped];

0 commit comments

Comments
 (0)
Please sign in to comment.