-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcollage-plugin.ts
120 lines (113 loc) · 3.84 KB
/
collage-plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import merge from 'lodash.mergewith';
import {
Collage, Plugin, PluginFunctions,
} from '../types';
/**
* D, E, P refer to
*
* Description, Enhanced and Provided and are used here for better readability
*/
/**
* Helper function to merge two contexts
* @param context
* @param append
*/
export function mergeContexts(context: unknown, append: unknown) {
merge(context, append, (c, a) => {
if (!c) {
return a;
}
if (!a) {
return c;
}
if (typeof c === 'object' && typeof a === 'object') {
if (!Object.entries(c).length) {
return a;
}
if (!Object.entries(a).length) {
return c;
}
}
return undefined;
});
}
/**
* Builds the context type returned by a call of expose in a micro-frontend by merging the existing context
* type with a plugin specific context type. This happens one after the other for each plugin.
*
* @param previous context before the plugin is called
* @param pluginFunction function returning the plugin specific context type and functions
* @returns the exposed function to be used in the micro-frontend.
* The exposed function then returns the merged context type.
*/
function buildContext<D, C, E>(
previous: (description: D) => C | Promise<C>, // "collage function"
pluginFunction: (description: D, context: C) => Promise<E> | E | void,
) {
return async (description: D) => {
const context = await previous(description);
const append = await pluginFunction((description || {}) as D, context);
mergeContexts(context as unknown as C, append as unknown as C);
return context as unknown as E;
};
}
/**
* Defines the enhanceUpdateContext function
*
* @param previous context before enhanceUpdateContext is called
* @param pluginFunction function to be appended to the context so it is available after the plugin is bootstrapped
* @returns the enhanced context
*/
function defineEnhanceUpdateContext<C, E>(
previous: (context: C) => C | Promise<C>, // "collage Function"
pluginFunction: (context: C) => Promise<E> | E | void,
) {
return async (context: E) => {
const previousContext = await previous(context as unknown as C);
const append = await pluginFunction(previousContext);
mergeContexts(context, append as E);
return context as unknown as E;
};
}
function extractPluginSpecificProperties<C, E>(
previous: (data: C) => E, // "collage Function"
pluginFunction: (data: C) => E,
) {
return (data: C) => {
const previousContext = previous(data as unknown as C);
const append = pluginFunction(data);
mergeContexts(previousContext, append as E);
return previousContext;
};
}
function concatReservedWords(previous: Array<string>, next?: Array<string>): Array<string> {
return next ? previous.concat(next) : previous;
}
export default function plugin<D, C, E>(
{
enhanceExpose,
enhanceUpdateContext = () => { /* noop */ },
reservedWords,
enhanceExtractContextAsArrangement = () => { /** noop */ },
enhanceExtractContextAsFragment = () => { /** noop */ },
enhanceExtractFragmentDescription = () => { /** noop */ },
}: PluginFunctions<D, C, E>,
): Plugin<D, C, E> {
return (previous: Collage<D, C>) => ({
expose: buildContext(previous.expose, enhanceExpose),
updateContext: defineEnhanceUpdateContext(previous.updateContext, enhanceUpdateContext),
reservedWords: concatReservedWords(previous.reservedWords, reservedWords),
extractContextAsArrangement: extractPluginSpecificProperties(
previous.extractContextAsArrangement,
enhanceExtractContextAsArrangement,
),
extractContextAsFragment: extractPluginSpecificProperties(
previous.extractContextAsFragment,
enhanceExtractContextAsFragment,
),
extractFragmentDescription: extractPluginSpecificProperties(
previous.extractFragmentDescription,
enhanceExtractFragmentDescription,
),
});
}