@openmrs/esm-config 10.0.1-pre.5635 → 10.0.1-pre.5649
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.turbo/turbo-build.log
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-config.d.ts","sourceRoot":"","sources":["../../src/module-config/module-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAuB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"module-config.d.ts","sourceRoot":"","sources":["../../src/module-config/module-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAuB,MAAM,UAAU,CAAC;AA4VxF;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,QAS1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,MAAM,QAKhE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,QAKpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,QAK7D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,QAetF;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,SAAa,QAK9D;AAiCD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAMjF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAoBxD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAKvG;AA6nBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,QAUjD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,SAYhC"}
|
|
@@ -43,14 +43,33 @@ const configSubscriptions = [];
|
|
|
43
43
|
const configState = configInternalStore.getState();
|
|
44
44
|
const tempConfigState = temporaryConfigStore.getState();
|
|
45
45
|
const extensionState = configExtensionStore.getState();
|
|
46
|
+
// Mounting an extension changes only `configExtensionStore`, which only the extension configs
|
|
47
|
+
// depend on, so the rest of the last derivation is reused.
|
|
48
|
+
const configInputsUnchanged = lastDerivation?.configState === configState && lastDerivation.tempConfigState === tempConfigState;
|
|
49
|
+
if (configInputsUnchanged) {
|
|
50
|
+
computeExtensionConfigs(configState, extensionState, tempConfigState, lastDerivation.slotConfigs, true);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
46
53
|
computeModuleConfig(configState, tempConfigState);
|
|
47
54
|
const slotConfigs = getExtensionSlotConfigs(configState, tempConfigState);
|
|
48
55
|
computeExtensionSlotConfigs(slotConfigs);
|
|
49
|
-
computeExtensionConfigs(configState, extensionState, tempConfigState, slotConfigs);
|
|
56
|
+
computeExtensionConfigs(configState, extensionState, tempConfigState, slotConfigs, false);
|
|
57
|
+
// Recorded only after the outputs above are written, so a failure forces a full derivation next time.
|
|
58
|
+
lastDerivation = {
|
|
59
|
+
configState,
|
|
60
|
+
tempConfigState,
|
|
61
|
+
slotConfigs
|
|
62
|
+
};
|
|
50
63
|
// Last, because a failure here must not skip the outputs above. Only kept current while the
|
|
51
64
|
// implementer tools are watching it; otherwise derived on read.
|
|
52
65
|
invalidateImplementerToolsConfig();
|
|
53
66
|
}
|
|
67
|
+
/** The inputs the outputs were last fully derived from, compared by identity. */ let lastDerivation = null;
|
|
68
|
+
/**
|
|
69
|
+
* The mounted extension each extension config entry was derived for. An extension ID can be
|
|
70
|
+
* mounted under a different module while its slot and ID stay the same, so an entry is only
|
|
71
|
+
* current if its modules match too.
|
|
72
|
+
*/ let entryOrigins = new WeakMap();
|
|
54
73
|
function setupConfigSubscriptions() {
|
|
55
74
|
// Registered here rather than at module load so that `resetConfigSystem` restores it.
|
|
56
75
|
setImplementerToolsConfigRecomputer(()=>computeImplementerToolsConfig(configInternalStore.getState(), temporaryConfigStore.getState()));
|
|
@@ -149,7 +168,7 @@ function computeImplementerToolsConfig(state, tempConfigState) {
|
|
|
149
168
|
implementerToolsConfigStore.setState(newState);
|
|
150
169
|
}
|
|
151
170
|
}
|
|
152
|
-
function computeExtensionConfigs(configState, extensionState, tempConfigState, slotConfigs) {
|
|
171
|
+
function computeExtensionConfigs(configState, extensionState, tempConfigState, slotConfigs, configInputsUnchanged) {
|
|
153
172
|
const extensionsConfigStore = getExtensionsConfigStore();
|
|
154
173
|
const oldConfigs = extensionsConfigStore.getState().configs;
|
|
155
174
|
const configs = {};
|
|
@@ -158,14 +177,22 @@ function computeExtensionConfigs(configState, extensionState, tempConfigState, s
|
|
|
158
177
|
// We assume that the module schema has already been defined, since the extension
|
|
159
178
|
// it contains is mounted.
|
|
160
179
|
for (let extension of extensionState.mountedExtensions){
|
|
161
|
-
const config = computeExtensionConfig(extension.slotModuleName, extension.extensionModuleName, extension.slotName, extension.extensionId, configState, tempConfigState, slotConfigs[extension.slotName]);
|
|
162
180
|
const previous = oldConfigs[extension.slotName]?.[extension.extensionId];
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
181
|
+
let entry;
|
|
182
|
+
const origin = previous && entryOrigins.get(previous);
|
|
183
|
+
if (configInputsUnchanged && previous?.loaded && origin?.slotModuleName === extension.slotModuleName && origin.extensionModuleName === extension.extensionModuleName) {
|
|
184
|
+
// Derived from these same inputs by the previous run, so it is still current.
|
|
185
|
+
entry = previous;
|
|
186
|
+
} else {
|
|
187
|
+
const config = computeExtensionConfig(extension.slotModuleName, extension.extensionModuleName, extension.slotName, extension.extensionId, configState, tempConfigState, slotConfigs[extension.slotName]);
|
|
188
|
+
// Entries keep their identity when the configuration behind them hasn't changed, so that
|
|
189
|
+
// mounting one extension doesn't hand every other mounted extension a new config object.
|
|
190
|
+
entry = previous?.loaded && isEqual(previous.config, config) ? previous : {
|
|
191
|
+
config,
|
|
192
|
+
loaded: true
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
entryOrigins.set(entry, extension);
|
|
169
196
|
if (entry !== previous) {
|
|
170
197
|
changed = true;
|
|
171
198
|
}
|
|
@@ -937,6 +964,8 @@ function logError(keyPath, message) {
|
|
|
937
964
|
extensionConfigCache.clear();
|
|
938
965
|
schemaValuesAndSourcesCache.clear();
|
|
939
966
|
implementerToolsModuleCache.clear();
|
|
967
|
+
lastDerivation = null;
|
|
968
|
+
entryOrigins = new WeakMap();
|
|
940
969
|
setupConfigSubscriptions();
|
|
941
970
|
}
|
|
942
971
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-config",
|
|
3
|
-
"version": "10.0.1-pre.
|
|
3
|
+
"version": "10.0.1-pre.5649",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "A configuration library for the OpenMRS Single-Spa framework.",
|
|
6
6
|
"type": "module",
|
|
@@ -57,15 +57,15 @@
|
|
|
57
57
|
"lodash-es": "^4.17.21"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@openmrs/esm-globals": "^10.0.1-pre.
|
|
61
|
-
"@openmrs/esm-state": "^10.0.1-pre.
|
|
62
|
-
"@openmrs/esm-utils": "^10.0.1-pre.
|
|
60
|
+
"@openmrs/esm-globals": "^10.0.1-pre.5649",
|
|
61
|
+
"@openmrs/esm-state": "^10.0.1-pre.5649",
|
|
62
|
+
"@openmrs/esm-utils": "^10.0.1-pre.5649",
|
|
63
63
|
"single-spa": "6.x"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@openmrs/esm-globals": "10.0.1-pre.
|
|
67
|
-
"@openmrs/esm-state": "10.0.1-pre.
|
|
68
|
-
"@openmrs/esm-utils": "10.0.1-pre.
|
|
66
|
+
"@openmrs/esm-globals": "10.0.1-pre.5649",
|
|
67
|
+
"@openmrs/esm-state": "10.0.1-pre.5649",
|
|
68
|
+
"@openmrs/esm-utils": "10.0.1-pre.5649",
|
|
69
69
|
"@swc/cli": "0.8.1",
|
|
70
70
|
"@swc/core": "1.15.21",
|
|
71
71
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -1304,6 +1304,54 @@ describe('extension config', () => {
|
|
|
1304
1304
|
expect(derivations).toBe(3);
|
|
1305
1305
|
});
|
|
1306
1306
|
|
|
1307
|
+
it('keeps every mounted extension current across config changes interleaved with mounts', () => {
|
|
1308
|
+
const mount = (extensionIds: Array<string>) =>
|
|
1309
|
+
configExtensionStore.setState({
|
|
1310
|
+
mountedExtensions: extensionIds.map((extensionId) => ({
|
|
1311
|
+
slotModuleName: 'slot-mod',
|
|
1312
|
+
extensionModuleName: 'ext-mod',
|
|
1313
|
+
slotName: 'barSlot',
|
|
1314
|
+
extensionId,
|
|
1315
|
+
})),
|
|
1316
|
+
});
|
|
1317
|
+
const bar = (extensionId: string) => getExtensionConfig('barSlot', extensionId).getState().config.bar;
|
|
1318
|
+
|
|
1319
|
+
mount(['fooExt#a']);
|
|
1320
|
+
expect(bar('fooExt#a')).toBe('barry');
|
|
1321
|
+
|
|
1322
|
+
temporaryConfigStore.setState({ config: { 'ext-mod': { bar: 'temporary' } } });
|
|
1323
|
+
expect(bar('fooExt#a')).toBe('temporary');
|
|
1324
|
+
|
|
1325
|
+
// Mounting with the config unchanged must neither revert the extension already mounted nor
|
|
1326
|
+
// hand the new one a config derived from anything but the current inputs.
|
|
1327
|
+
mount(['fooExt#a', 'fooExt#b']);
|
|
1328
|
+
expect(bar('fooExt#a')).toBe('temporary');
|
|
1329
|
+
expect(bar('fooExt#b')).toBe('temporary');
|
|
1330
|
+
|
|
1331
|
+
temporaryConfigStore.setState({ config: {} });
|
|
1332
|
+
expect(bar('fooExt#a')).toBe('barry');
|
|
1333
|
+
expect(bar('fooExt#b')).toBe('barry');
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
it('re-derives the config of an extension mounted again under a different module', () => {
|
|
1337
|
+
Config.defineConfigSchema('other-mod', { bar: { _default: 'other' } });
|
|
1338
|
+
Config.registerModuleLoad('other-mod');
|
|
1339
|
+
|
|
1340
|
+
const mount = (extensionModuleName: string) =>
|
|
1341
|
+
configExtensionStore.setState({
|
|
1342
|
+
mountedExtensions: [
|
|
1343
|
+
{ slotModuleName: 'slot-mod', extensionModuleName, slotName: 'barSlot', extensionId: 'fooExt' },
|
|
1344
|
+
],
|
|
1345
|
+
});
|
|
1346
|
+
const bar = () => getExtensionConfig('barSlot', 'fooExt').getState().config.bar;
|
|
1347
|
+
|
|
1348
|
+
mount('ext-mod');
|
|
1349
|
+
expect(bar()).toBe('barry');
|
|
1350
|
+
|
|
1351
|
+
mount('other-mod');
|
|
1352
|
+
expect(bar()).toBe('other');
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1307
1355
|
it('returns the module config', async () => {
|
|
1308
1356
|
const moduleLevelConfig = { 'ext-mod': { bar: 'qux' } };
|
|
1309
1357
|
updateConfigExtensionStore();
|
|
@@ -6,6 +6,7 @@ import { isArray, isBoolean, isUuid, isNumber, isObject, isString } from '../val
|
|
|
6
6
|
import { validator } from '../validators/validator';
|
|
7
7
|
import {
|
|
8
8
|
type ConfigExtensionStore,
|
|
9
|
+
type ConfigExtensionStoreElement,
|
|
9
10
|
type ConfigInternalStore,
|
|
10
11
|
type ConfigStore,
|
|
11
12
|
type ExtensionSlotsConfigStore,
|
|
@@ -74,17 +75,44 @@ function recomputeAllConfigs() {
|
|
|
74
75
|
const tempConfigState = temporaryConfigStore.getState();
|
|
75
76
|
const extensionState = configExtensionStore.getState();
|
|
76
77
|
|
|
78
|
+
// Mounting an extension changes only `configExtensionStore`, which only the extension configs
|
|
79
|
+
// depend on, so the rest of the last derivation is reused.
|
|
80
|
+
const configInputsUnchanged =
|
|
81
|
+
lastDerivation?.configState === configState && lastDerivation.tempConfigState === tempConfigState;
|
|
82
|
+
|
|
83
|
+
if (configInputsUnchanged) {
|
|
84
|
+
computeExtensionConfigs(configState, extensionState, tempConfigState, lastDerivation!.slotConfigs, true);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
77
88
|
computeModuleConfig(configState, tempConfigState);
|
|
78
89
|
|
|
79
90
|
const slotConfigs = getExtensionSlotConfigs(configState, tempConfigState);
|
|
80
91
|
computeExtensionSlotConfigs(slotConfigs);
|
|
81
|
-
computeExtensionConfigs(configState, extensionState, tempConfigState, slotConfigs);
|
|
92
|
+
computeExtensionConfigs(configState, extensionState, tempConfigState, slotConfigs, false);
|
|
93
|
+
|
|
94
|
+
// Recorded only after the outputs above are written, so a failure forces a full derivation next time.
|
|
95
|
+
lastDerivation = { configState, tempConfigState, slotConfigs };
|
|
82
96
|
|
|
83
97
|
// Last, because a failure here must not skip the outputs above. Only kept current while the
|
|
84
98
|
// implementer tools are watching it; otherwise derived on read.
|
|
85
99
|
invalidateImplementerToolsConfig();
|
|
86
100
|
}
|
|
87
101
|
|
|
102
|
+
/** The inputs the outputs were last fully derived from, compared by identity. */
|
|
103
|
+
let lastDerivation: {
|
|
104
|
+
configState: ConfigInternalStore;
|
|
105
|
+
tempConfigState: TemporaryConfigStore;
|
|
106
|
+
slotConfigs: Record<string, ExtensionSlotConfig>;
|
|
107
|
+
} | null = null;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The mounted extension each extension config entry was derived for. An extension ID can be
|
|
111
|
+
* mounted under a different module while its slot and ID stay the same, so an entry is only
|
|
112
|
+
* current if its modules match too.
|
|
113
|
+
*/
|
|
114
|
+
let entryOrigins = new WeakMap<object, ConfigExtensionStoreElement>();
|
|
115
|
+
|
|
88
116
|
function setupConfigSubscriptions() {
|
|
89
117
|
// Registered here rather than at module load so that `resetConfigSystem` restores it.
|
|
90
118
|
setImplementerToolsConfigRecomputer(() =>
|
|
@@ -233,6 +261,7 @@ function computeExtensionConfigs(
|
|
|
233
261
|
extensionState: ConfigExtensionStore,
|
|
234
262
|
tempConfigState: TemporaryConfigStore,
|
|
235
263
|
slotConfigs: Record<string, ExtensionSlotConfig>,
|
|
264
|
+
configInputsUnchanged: boolean,
|
|
236
265
|
) {
|
|
237
266
|
const extensionsConfigStore = getExtensionsConfigStore();
|
|
238
267
|
const oldConfigs = extensionsConfigStore.getState().configs;
|
|
@@ -243,20 +272,36 @@ function computeExtensionConfigs(
|
|
|
243
272
|
// We assume that the module schema has already been defined, since the extension
|
|
244
273
|
// it contains is mounted.
|
|
245
274
|
for (let extension of extensionState.mountedExtensions) {
|
|
246
|
-
const config = computeExtensionConfig(
|
|
247
|
-
extension.slotModuleName,
|
|
248
|
-
extension.extensionModuleName,
|
|
249
|
-
extension.slotName,
|
|
250
|
-
extension.extensionId,
|
|
251
|
-
configState,
|
|
252
|
-
tempConfigState,
|
|
253
|
-
slotConfigs[extension.slotName],
|
|
254
|
-
);
|
|
255
|
-
|
|
256
275
|
const previous = oldConfigs[extension.slotName]?.[extension.extensionId];
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
276
|
+
let entry: ConfigStore | { config: ConfigObject; loaded: true };
|
|
277
|
+
|
|
278
|
+
const origin = previous && entryOrigins.get(previous);
|
|
279
|
+
|
|
280
|
+
if (
|
|
281
|
+
configInputsUnchanged &&
|
|
282
|
+
previous?.loaded &&
|
|
283
|
+
origin?.slotModuleName === extension.slotModuleName &&
|
|
284
|
+
origin.extensionModuleName === extension.extensionModuleName
|
|
285
|
+
) {
|
|
286
|
+
// Derived from these same inputs by the previous run, so it is still current.
|
|
287
|
+
entry = previous;
|
|
288
|
+
} else {
|
|
289
|
+
const config = computeExtensionConfig(
|
|
290
|
+
extension.slotModuleName,
|
|
291
|
+
extension.extensionModuleName,
|
|
292
|
+
extension.slotName,
|
|
293
|
+
extension.extensionId,
|
|
294
|
+
configState,
|
|
295
|
+
tempConfigState,
|
|
296
|
+
slotConfigs[extension.slotName],
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// Entries keep their identity when the configuration behind them hasn't changed, so that
|
|
300
|
+
// mounting one extension doesn't hand every other mounted extension a new config object.
|
|
301
|
+
entry = previous?.loaded && isEqual(previous.config, config) ? previous : { config, loaded: true };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
entryOrigins.set(entry, extension);
|
|
260
305
|
|
|
261
306
|
if (entry !== previous) {
|
|
262
307
|
changed = true;
|
|
@@ -1198,6 +1243,8 @@ export function resetConfigSystem() {
|
|
|
1198
1243
|
extensionConfigCache.clear();
|
|
1199
1244
|
schemaValuesAndSourcesCache.clear();
|
|
1200
1245
|
implementerToolsModuleCache.clear();
|
|
1246
|
+
lastDerivation = null;
|
|
1247
|
+
entryOrigins = new WeakMap();
|
|
1201
1248
|
setupConfigSubscriptions();
|
|
1202
1249
|
}
|
|
1203
1250
|
|