repluggable-core 1.302.66 → 1.302.67
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/__tests__/spec-setup.js +3 -0
- package/dist/es/{API.d.ts → src/API.d.ts} +46 -8
- package/dist/es/src/API.d.ts.map +1 -0
- package/dist/es/src/API.js +3 -0
- package/dist/es/src/API.js.map +1 -0
- package/dist/es/src/IterableWeakMap.d.ts +20 -0
- package/dist/es/src/IterableWeakMap.d.ts.map +1 -0
- package/dist/es/src/IterableWeakMap.js +92 -0
- package/dist/es/src/IterableWeakMap.js.map +1 -0
- package/dist/es/src/__internal.d.ts.map +1 -0
- package/dist/es/src/__internal.js +5 -0
- package/dist/es/src/__internal.js.map +1 -0
- package/dist/es/src/appHost.d.ts +7 -0
- package/dist/es/src/appHost.d.ts.map +1 -0
- package/dist/es/src/appHost.js +898 -0
- package/dist/es/src/appHost.js.map +1 -0
- package/dist/es/src/appHostServices.d.ts +12 -0
- package/dist/es/src/appHostServices.d.ts.map +1 -0
- package/dist/es/src/appHostServices.js +25 -0
- package/dist/es/src/appHostServices.js.map +1 -0
- package/dist/es/src/appHostUtils.d.ts +4 -0
- package/dist/es/src/appHostUtils.d.ts.map +1 -0
- package/dist/es/src/appHostUtils.js +8 -0
- package/dist/es/src/appHostUtils.js.map +1 -0
- package/dist/es/src/extensionSlot.d.ts +8 -0
- package/dist/es/src/extensionSlot.d.ts.map +1 -0
- package/dist/es/src/extensionSlot.js +59 -0
- package/dist/es/src/extensionSlot.js.map +1 -0
- package/dist/es/src/hot.d.ts +14 -0
- package/dist/es/src/hot.d.ts.map +1 -0
- package/dist/es/src/hot.js +52 -0
- package/dist/es/src/hot.js.map +1 -0
- package/dist/es/src/index.d.ts +11 -0
- package/dist/es/src/index.d.ts.map +1 -0
- package/dist/es/src/index.js +10 -0
- package/dist/es/src/index.js.map +1 -0
- package/dist/es/src/installedShellsState.d.ts +19 -0
- package/dist/es/src/installedShellsState.d.ts.map +1 -0
- package/dist/es/src/installedShellsState.js +30 -0
- package/dist/es/src/installedShellsState.js.map +1 -0
- package/dist/es/src/interceptAnyObject.d.ts +7 -0
- package/dist/es/src/interceptAnyObject.d.ts.map +1 -0
- package/dist/es/src/interceptAnyObject.js +21 -0
- package/dist/es/src/interceptAnyObject.js.map +1 -0
- package/dist/es/src/invokeSlotCallbacks.d.ts +3 -0
- package/dist/es/src/invokeSlotCallbacks.d.ts.map +1 -0
- package/dist/es/src/invokeSlotCallbacks.js +20 -0
- package/dist/es/src/invokeSlotCallbacks.js.map +1 -0
- package/dist/es/src/loggers.d.ts +4 -0
- package/dist/es/src/loggers.d.ts.map +1 -0
- package/dist/es/src/loggers.js +100 -0
- package/dist/es/src/loggers.js.map +1 -0
- package/dist/es/src/monitorAPI.d.ts +3 -0
- package/dist/es/src/monitorAPI.d.ts.map +1 -0
- package/dist/es/src/monitorAPI.js +53 -0
- package/dist/es/src/monitorAPI.js.map +1 -0
- package/dist/es/src/repluggableAppDebug/index.d.ts +2 -0
- package/dist/es/src/repluggableAppDebug/index.d.ts.map +1 -0
- package/dist/es/src/repluggableAppDebug/index.js +2 -0
- package/dist/es/src/repluggableAppDebug/index.js.map +1 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.d.ts +15 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.d.ts.map +1 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.js +94 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.js.map +1 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts +24 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js +132 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -0
- package/dist/es/src/tarjanGraph.d.ts +27 -0
- package/dist/es/src/tarjanGraph.d.ts.map +1 -0
- package/dist/es/src/tarjanGraph.js +94 -0
- package/dist/es/src/tarjanGraph.js.map +1 -0
- package/dist/es/src/throttledStore.d.ts +32 -0
- package/dist/es/src/throttledStore.d.ts.map +1 -0
- package/dist/es/src/throttledStore.js +240 -0
- package/dist/es/src/throttledStore.js.map +1 -0
- package/dist/es/test/IterableWeakMap.spec.d.ts +2 -0
- package/dist/es/test/IterableWeakMap.spec.d.ts.map +1 -0
- package/dist/es/test/IterableWeakMap.spec.js +218 -0
- package/dist/es/test/IterableWeakMap.spec.js.map +1 -0
- package/dist/es/test/appHost.mock.d.ts +4 -0
- package/dist/es/test/appHost.mock.d.ts.map +1 -0
- package/dist/es/test/appHost.mock.js +54 -0
- package/dist/es/test/appHost.mock.js.map +1 -0
- package/dist/es/test/appHost.spec.d.ts +2 -0
- package/dist/es/test/appHost.spec.d.ts.map +1 -0
- package/dist/es/test/appHost.spec.js +1451 -0
- package/dist/es/test/appHost.spec.js.map +1 -0
- package/dist/es/test/installedShellsState.spec.d.ts +2 -0
- package/dist/es/test/installedShellsState.spec.d.ts.map +1 -0
- package/dist/es/test/installedShellsState.spec.js +28 -0
- package/dist/es/test/installedShellsState.spec.js.map +1 -0
- package/dist/es/test/interceptAnyObject.spec.d.ts +2 -0
- package/dist/es/test/interceptAnyObject.spec.d.ts.map +1 -0
- package/dist/es/test/interceptAnyObject.spec.js +166 -0
- package/dist/es/test/interceptAnyObject.spec.js.map +1 -0
- package/dist/es/test/loggers.spec.d.ts +2 -0
- package/dist/es/test/loggers.spec.d.ts.map +1 -0
- package/dist/es/test/loggers.spec.js +218 -0
- package/dist/es/test/loggers.spec.js.map +1 -0
- package/dist/es/test/repluggableAppDebug.spec.d.ts +2 -0
- package/dist/es/test/repluggableAppDebug.spec.d.ts.map +1 -0
- package/dist/es/test/repluggableAppDebug.spec.js +107 -0
- package/dist/es/test/repluggableAppDebug.spec.js.map +1 -0
- package/dist/es/test/testKit.spec.d.ts +2 -0
- package/dist/es/test/testKit.spec.d.ts.map +1 -0
- package/dist/es/test/testKit.spec.js +129 -0
- package/dist/es/test/testKit.spec.js.map +1 -0
- package/dist/es/testKit/emptyLoggerOptions.d.ts +3 -0
- package/dist/es/testKit/emptyLoggerOptions.d.ts.map +1 -0
- package/dist/es/testKit/emptyLoggerOptions.js +15 -0
- package/dist/es/testKit/emptyLoggerOptions.js.map +1 -0
- package/dist/es/testKit/index.d.ts +27 -0
- package/dist/es/testKit/index.d.ts.map +1 -0
- package/dist/es/testKit/index.js +132 -0
- package/dist/es/testKit/index.js.map +1 -0
- package/dist/es/testKit/mockPackage.d.ts +23 -0
- package/dist/es/testKit/mockPackage.d.ts.map +1 -0
- package/dist/es/testKit/mockPackage.js +95 -0
- package/dist/es/testKit/mockPackage.js.map +1 -0
- package/dist/es/testKit/withConsoleErrors.d.ts +2 -0
- package/dist/es/testKit/withConsoleErrors.d.ts.map +1 -0
- package/dist/es/testKit/withConsoleErrors.js +12 -0
- package/dist/es/testKit/withConsoleErrors.js.map +1 -0
- package/dist/es/testKit/withThrowOnError.d.ts +3 -0
- package/dist/es/testKit/withThrowOnError.d.ts.map +1 -0
- package/dist/es/testKit/withThrowOnError.js +27 -0
- package/dist/es/testKit/withThrowOnError.js.map +1 -0
- package/dist/src/API.d.ts +46 -8
- package/dist/src/API.d.ts.map +1 -1
- package/dist/src/API.js +4 -0
- package/dist/src/API.js.map +1 -1
- package/dist/src/IterableWeakMap.d.ts +20 -0
- package/dist/src/IterableWeakMap.d.ts.map +1 -0
- package/dist/src/IterableWeakMap.js +96 -0
- package/dist/src/IterableWeakMap.js.map +1 -0
- package/dist/src/__internal.d.ts.map +1 -1
- package/dist/src/__internal.js +1 -1
- package/dist/src/__internal.js.map +1 -1
- package/dist/src/appHost.d.ts +7 -0
- package/dist/src/appHost.d.ts.map +1 -0
- package/dist/src/appHost.js +906 -0
- package/dist/src/appHost.js.map +1 -0
- package/dist/src/appHostServices.d.ts +12 -0
- package/dist/src/appHostServices.d.ts.map +1 -0
- package/dist/src/appHostServices.js +29 -0
- package/dist/src/appHostServices.js.map +1 -0
- package/dist/src/appHostUtils.d.ts +4 -0
- package/dist/src/appHostUtils.d.ts.map +1 -0
- package/dist/src/appHostUtils.js +16 -0
- package/dist/src/appHostUtils.js.map +1 -0
- package/dist/src/extensionSlot.d.ts +8 -0
- package/dist/src/extensionSlot.d.ts.map +1 -0
- package/dist/src/extensionSlot.js +67 -0
- package/dist/src/extensionSlot.js.map +1 -0
- package/dist/src/hot.d.ts +14 -0
- package/dist/src/hot.d.ts.map +1 -0
- package/dist/src/hot.js +56 -0
- package/dist/src/hot.js.map +1 -0
- package/dist/src/index.d.ts +10 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +22 -15
- package/dist/src/index.js.map +1 -1
- package/dist/src/installedShellsState.d.ts +19 -0
- package/dist/src/installedShellsState.d.ts.map +1 -0
- package/dist/src/installedShellsState.js +38 -0
- package/dist/src/installedShellsState.js.map +1 -0
- package/dist/src/interceptAnyObject.d.ts +7 -0
- package/dist/src/interceptAnyObject.d.ts.map +1 -0
- package/dist/src/interceptAnyObject.js +28 -0
- package/dist/src/interceptAnyObject.js.map +1 -0
- package/dist/src/invokeSlotCallbacks.d.ts +3 -0
- package/dist/src/invokeSlotCallbacks.d.ts.map +1 -0
- package/dist/src/invokeSlotCallbacks.js +24 -0
- package/dist/src/invokeSlotCallbacks.js.map +1 -0
- package/dist/src/loggers.d.ts +4 -0
- package/dist/src/loggers.d.ts.map +1 -0
- package/dist/src/loggers.js +104 -0
- package/dist/src/loggers.js.map +1 -0
- package/dist/src/monitorAPI.d.ts +3 -0
- package/dist/src/monitorAPI.d.ts.map +1 -0
- package/dist/src/monitorAPI.js +57 -0
- package/dist/src/monitorAPI.js.map +1 -0
- package/dist/src/repluggableAppDebug/index.d.ts +2 -0
- package/dist/src/repluggableAppDebug/index.d.ts.map +1 -0
- package/dist/src/repluggableAppDebug/index.js +6 -0
- package/dist/src/repluggableAppDebug/index.js.map +1 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.d.ts +15 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.d.ts.map +1 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.js +101 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.js.map +1 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts +24 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js +139 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -0
- package/dist/src/tarjanGraph.d.ts +27 -0
- package/dist/src/tarjanGraph.d.ts.map +1 -0
- package/dist/src/tarjanGraph.js +100 -0
- package/dist/src/tarjanGraph.js.map +1 -0
- package/dist/src/throttledStore.d.ts +32 -0
- package/dist/src/throttledStore.d.ts.map +1 -0
- package/dist/src/throttledStore.js +249 -0
- package/dist/src/throttledStore.js.map +1 -0
- package/dist/test/IterableWeakMap.spec.d.ts +2 -0
- package/dist/test/IterableWeakMap.spec.d.ts.map +1 -0
- package/dist/test/IterableWeakMap.spec.js +220 -0
- package/dist/test/IterableWeakMap.spec.js.map +1 -0
- package/dist/test/appHost.mock.d.ts +4 -0
- package/dist/test/appHost.mock.d.ts.map +1 -0
- package/dist/test/appHost.mock.js +59 -0
- package/dist/test/appHost.mock.js.map +1 -0
- package/dist/test/appHost.spec.d.ts +2 -0
- package/dist/test/appHost.spec.d.ts.map +1 -0
- package/dist/test/appHost.spec.js +1456 -0
- package/dist/test/appHost.spec.js.map +1 -0
- package/dist/test/installedShellsState.spec.d.ts +2 -0
- package/dist/test/installedShellsState.spec.d.ts.map +1 -0
- package/dist/test/installedShellsState.spec.js +30 -0
- package/dist/test/installedShellsState.spec.js.map +1 -0
- package/dist/test/interceptAnyObject.spec.d.ts +2 -0
- package/dist/test/interceptAnyObject.spec.d.ts.map +1 -0
- package/dist/test/interceptAnyObject.spec.js +171 -0
- package/dist/test/interceptAnyObject.spec.js.map +1 -0
- package/dist/test/loggers.spec.d.ts +2 -0
- package/dist/test/loggers.spec.d.ts.map +1 -0
- package/dist/test/loggers.spec.js +220 -0
- package/dist/test/loggers.spec.js.map +1 -0
- package/dist/test/repluggableAppDebug.spec.d.ts +2 -0
- package/dist/test/repluggableAppDebug.spec.d.ts.map +1 -0
- package/dist/test/repluggableAppDebug.spec.js +109 -0
- package/dist/test/repluggableAppDebug.spec.js.map +1 -0
- package/dist/test/testKit.spec.d.ts +2 -0
- package/dist/test/testKit.spec.d.ts.map +1 -0
- package/dist/test/testKit.spec.js +134 -0
- package/dist/test/testKit.spec.js.map +1 -0
- package/dist/testKit/emptyLoggerOptions.d.ts +3 -0
- package/dist/testKit/emptyLoggerOptions.d.ts.map +1 -0
- package/dist/testKit/emptyLoggerOptions.js +18 -0
- package/dist/testKit/emptyLoggerOptions.js.map +1 -0
- package/dist/testKit/index.d.ts +27 -0
- package/dist/testKit/index.d.ts.map +1 -0
- package/dist/testKit/index.js +160 -0
- package/dist/testKit/index.js.map +1 -0
- package/dist/testKit/mockPackage.d.ts +23 -0
- package/dist/testKit/mockPackage.d.ts.map +1 -0
- package/dist/testKit/mockPackage.js +101 -0
- package/dist/testKit/mockPackage.js.map +1 -0
- package/dist/testKit/withConsoleErrors.d.ts +2 -0
- package/dist/testKit/withConsoleErrors.d.ts.map +1 -0
- package/dist/testKit/withConsoleErrors.js +16 -0
- package/dist/testKit/withConsoleErrors.js.map +1 -0
- package/dist/testKit/withThrowOnError.d.ts +3 -0
- package/dist/testKit/withThrowOnError.d.ts.map +1 -0
- package/dist/testKit/withThrowOnError.js +31 -0
- package/dist/testKit/withThrowOnError.js.map +1 -0
- package/jest.config.js +16 -0
- package/package.json +21 -3
- package/src/API.ts +47 -9
- package/src/IterableWeakMap.ts +123 -0
- package/src/__internal.ts +1 -1
- package/src/appHost.ts +1222 -0
- package/src/appHostServices.ts +42 -0
- package/src/appHostUtils.ts +11 -0
- package/src/extensionSlot.ts +96 -0
- package/src/hot.ts +53 -0
- package/src/index.ts +42 -2
- package/src/installedShellsState.ts +54 -0
- package/src/interceptAnyObject.ts +39 -0
- package/src/invokeSlotCallbacks.ts +20 -0
- package/src/loggers.ts +112 -0
- package/src/monitorAPI.ts +71 -0
- package/src/repluggableAppDebug/debug.d.ts +37 -0
- package/src/repluggableAppDebug/index.ts +1 -0
- package/src/repluggableAppDebug/performanceDebugInfo.ts +96 -0
- package/src/repluggableAppDebug/repluggableAppDebug.ts +192 -0
- package/src/tarjanGraph.ts +96 -0
- package/src/throttledStore.ts +355 -0
- package/test/IterableWeakMap.spec.ts +280 -0
- package/test/appHost.mock.ts +58 -0
- package/test/appHost.spec.ts +1765 -0
- package/test/installedShellsState.spec.ts +39 -0
- package/test/interceptAnyObject.spec.ts +217 -0
- package/test/loggers.spec.ts +288 -0
- package/test/repluggableAppDebug.spec.ts +118 -0
- package/test/testKit.spec.tsx +153 -0
- package/testKit/emptyLoggerOptions.ts +16 -0
- package/testKit/index.ts +170 -0
- package/testKit/mockPackage.ts +110 -0
- package/testKit/package.json +3 -0
- package/testKit/withConsoleErrors.ts +12 -0
- package/testKit/withThrowOnError.ts +34 -0
- package/tsconfig.json +9 -2
- package/dist/es/API.d.ts.map +0 -1
- package/dist/es/API.js +0 -2
- package/dist/es/API.js.map +0 -1
- package/dist/es/__internal.d.ts.map +0 -1
- package/dist/es/__internal.js +0 -5
- package/dist/es/__internal.js.map +0 -1
- package/dist/es/index.d.ts +0 -3
- package/dist/es/index.d.ts.map +0 -1
- package/dist/es/index.js +0 -2
- package/dist/es/index.js.map +0 -1
- /package/dist/es/{__internal.d.ts → src/__internal.d.ts} +0 -0
|
@@ -0,0 +1,898 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { createAppHostServicesEntryPoint } from './appHostServices';
|
|
3
|
+
import { declaredAPIs, dependentAPIs } from './appHostUtils';
|
|
4
|
+
import { createCustomExtensionSlot, createExtensionSlot } from './extensionSlot';
|
|
5
|
+
import { InstalledShellsActions, InstalledShellsSelectors } from './installedShellsState';
|
|
6
|
+
import { IterableWeakMap } from './IterableWeakMap';
|
|
7
|
+
import { ConsoleHostLogger, createShellLogger } from './loggers';
|
|
8
|
+
import { monitorAPI } from './monitorAPI';
|
|
9
|
+
import { setupDebugInfo } from './repluggableAppDebug';
|
|
10
|
+
import { getCycle, Graph, Tarjan } from './tarjanGraph';
|
|
11
|
+
import { createObservable, createThrottledStore, updateThrottledStore } from './throttledStore';
|
|
12
|
+
import { INTERNAL_DONT_USE_SHELL_GET_APP_HOST } from './__internal';
|
|
13
|
+
function isMultiArray(v) {
|
|
14
|
+
return _.every(v, _.isArray);
|
|
15
|
+
}
|
|
16
|
+
function castMultiArray(v) {
|
|
17
|
+
return isMultiArray(v) ? v : [v];
|
|
18
|
+
}
|
|
19
|
+
export const makeLazyEntryPoint = (name, factory) => {
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
factory
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export const mainViewSlotKey = {
|
|
26
|
+
name: 'mainView'
|
|
27
|
+
};
|
|
28
|
+
export const stateSlotKey = {
|
|
29
|
+
name: 'state'
|
|
30
|
+
};
|
|
31
|
+
const toShellToggleSet = (names, isInstalled) => {
|
|
32
|
+
return names.reduce((result, name) => {
|
|
33
|
+
result[name] = isInstalled;
|
|
34
|
+
return result;
|
|
35
|
+
}, {});
|
|
36
|
+
};
|
|
37
|
+
const createUnreadyEntryPointsStore = () => {
|
|
38
|
+
let entryPoints = [];
|
|
39
|
+
return {
|
|
40
|
+
get() {
|
|
41
|
+
return entryPoints;
|
|
42
|
+
},
|
|
43
|
+
set(newEntryPoints) {
|
|
44
|
+
entryPoints = newEntryPoints;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
const verifyLayersUniqueness = (layers) => {
|
|
49
|
+
if (!layers) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const flatLayers = _.flatten(layers);
|
|
53
|
+
const nonUnique = _(flatLayers)
|
|
54
|
+
.countBy(({ name }) => name)
|
|
55
|
+
.pickBy(v => v > 1)
|
|
56
|
+
.keys()
|
|
57
|
+
.value();
|
|
58
|
+
if (nonUnique.length > 0) {
|
|
59
|
+
throw new Error(`Cannot initialize host with non unique layers: ${nonUnique}`);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
export function createAppHost(initialEntryPointsOrPackages, options = { monitoring: {} }) {
|
|
63
|
+
let store = null;
|
|
64
|
+
let isInstallingEntryPoints = false;
|
|
65
|
+
let isStoreSubscribersNotifyInProgress = false;
|
|
66
|
+
let isObserversNotifyInProgress = false;
|
|
67
|
+
let shouldFlushMemoizationSync = false;
|
|
68
|
+
let isBatchingDeclarationsChangedCallbacks = false;
|
|
69
|
+
const entryPointsInstallationEndCallbacks = new Map();
|
|
70
|
+
verifyLayersUniqueness(options.layers);
|
|
71
|
+
const unReadyEntryPointsStore = createUnreadyEntryPointsStore();
|
|
72
|
+
const layers = _.map(options.layers ? castMultiArray(options.layers) : [], (singleDimension, i) => _.map(singleDimension, layer => (Object.assign(Object.assign({}, layer), { dimension: i }))));
|
|
73
|
+
const trace = [];
|
|
74
|
+
const memoizedArr = [];
|
|
75
|
+
const readyAPIs = new Set();
|
|
76
|
+
const createExtensionSlotsMap = () => {
|
|
77
|
+
const originalMap = new Map();
|
|
78
|
+
const proxyHandler = {
|
|
79
|
+
get(target, propertyName) {
|
|
80
|
+
if (propertyName === 'set') {
|
|
81
|
+
return function (key, value) {
|
|
82
|
+
return batchDeclarationsChangedCallbacks(() => target.set(key, value));
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (propertyName === 'delete') {
|
|
86
|
+
return function (key) {
|
|
87
|
+
return batchDeclarationsChangedCallbacks(() => target.delete(key));
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const originalProperty = target[propertyName];
|
|
91
|
+
if (typeof originalProperty === 'function') {
|
|
92
|
+
return originalProperty.bind(target);
|
|
93
|
+
}
|
|
94
|
+
return originalProperty;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
return new Proxy(originalMap, proxyHandler);
|
|
98
|
+
};
|
|
99
|
+
const uniqueShellNames = new Set();
|
|
100
|
+
const extensionSlots = createExtensionSlotsMap();
|
|
101
|
+
const slotKeysByName = new Map();
|
|
102
|
+
const addedShells = new Map();
|
|
103
|
+
const shellInstallers = new WeakMap();
|
|
104
|
+
const lazyShells = new Map();
|
|
105
|
+
const shellsChangedCallbacks = new Map();
|
|
106
|
+
const declarationsChangedCallbacks = new Map();
|
|
107
|
+
const APILayers = new WeakMap();
|
|
108
|
+
const memoizedFunctions = new IterableWeakMap();
|
|
109
|
+
let shouldFlushMemoization = false;
|
|
110
|
+
const hostAPI = {
|
|
111
|
+
getAllEntryPoints: () => [...addedShells.entries()].map(([, { entryPoint }]) => entryPoint),
|
|
112
|
+
getAppHostOptions: () => options
|
|
113
|
+
};
|
|
114
|
+
const appHostServicesEntryPoint = createAppHostServicesEntryPoint(() => hostAPI);
|
|
115
|
+
const host = {
|
|
116
|
+
getStore,
|
|
117
|
+
getAPI,
|
|
118
|
+
hasAPI,
|
|
119
|
+
getSlot,
|
|
120
|
+
hasSlot,
|
|
121
|
+
getAllSlotKeys,
|
|
122
|
+
getAllEntryPoints,
|
|
123
|
+
hasShell,
|
|
124
|
+
isLazyEntryPoint,
|
|
125
|
+
addShells,
|
|
126
|
+
removeShells,
|
|
127
|
+
onShellsChanged,
|
|
128
|
+
onDeclarationsChanged,
|
|
129
|
+
removeShellsChangedCallback,
|
|
130
|
+
getAppHostServicesShell: appHostServicesEntryPoint.getAppHostServicesShell,
|
|
131
|
+
log: options.logger ? options.logger : ConsoleHostLogger,
|
|
132
|
+
options,
|
|
133
|
+
executeWhenFree
|
|
134
|
+
};
|
|
135
|
+
setupDebugInfo({
|
|
136
|
+
host,
|
|
137
|
+
readyAPIs,
|
|
138
|
+
uniqueShellNames,
|
|
139
|
+
extensionSlots,
|
|
140
|
+
addedShells,
|
|
141
|
+
shellInstallers,
|
|
142
|
+
lazyShells,
|
|
143
|
+
performance: {
|
|
144
|
+
options,
|
|
145
|
+
trace,
|
|
146
|
+
memoizedArr
|
|
147
|
+
},
|
|
148
|
+
getUnreadyEntryPoints: unReadyEntryPointsStore.get,
|
|
149
|
+
getOwnSlotKey,
|
|
150
|
+
getAPI
|
|
151
|
+
});
|
|
152
|
+
declareSlot(mainViewSlotKey);
|
|
153
|
+
declareSlot(stateSlotKey);
|
|
154
|
+
addShells([appHostServicesEntryPoint]);
|
|
155
|
+
const memoize = (func, resolver) => {
|
|
156
|
+
if (options.monitoring.disableMemoization) {
|
|
157
|
+
return func;
|
|
158
|
+
}
|
|
159
|
+
const memoized = _.memoize(func, resolver);
|
|
160
|
+
if (options.monitoring.debugMemoization) {
|
|
161
|
+
Object.defineProperty(memoized, 'name', { value: `${func.name}_memoized`, writable: false });
|
|
162
|
+
}
|
|
163
|
+
if (options.monitoring.disableMonitoring) {
|
|
164
|
+
return memoized;
|
|
165
|
+
}
|
|
166
|
+
const enrichedMemoization = enrichMemoization(memoized);
|
|
167
|
+
if (options.monitoring.debugMemoization) {
|
|
168
|
+
return (...args) => {
|
|
169
|
+
const memRes = enrichedMemoization(...args);
|
|
170
|
+
const res = func(...args);
|
|
171
|
+
if (!_.isEqual(memRes, res)) {
|
|
172
|
+
console.log(`Memoization Error`);
|
|
173
|
+
console.log(`Memoization returns:`, memRes);
|
|
174
|
+
console.log(`Original Func returns:`, res);
|
|
175
|
+
console.log(`Original Func:`, func);
|
|
176
|
+
}
|
|
177
|
+
return memRes;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return enrichedMemoization;
|
|
181
|
+
};
|
|
182
|
+
function lazyEvaluator(fn) {
|
|
183
|
+
let _value;
|
|
184
|
+
let _resolved = false;
|
|
185
|
+
return {
|
|
186
|
+
get: () => {
|
|
187
|
+
if (!_resolved) {
|
|
188
|
+
_value = fn();
|
|
189
|
+
_resolved = true;
|
|
190
|
+
}
|
|
191
|
+
return _value;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// we know that addShells completes synchronously
|
|
196
|
+
addShells(initialEntryPointsOrPackages);
|
|
197
|
+
return host;
|
|
198
|
+
//TODO: get rid of LazyEntryPointDescriptor
|
|
199
|
+
function isLazyEntryPointDescriptor(value) {
|
|
200
|
+
return typeof value.factory === 'function';
|
|
201
|
+
}
|
|
202
|
+
function enrichMemoization(memoized) {
|
|
203
|
+
const memoizedWithMissHit = _.assign(memoized, {
|
|
204
|
+
miss: 0,
|
|
205
|
+
calls: 0,
|
|
206
|
+
hit: 0,
|
|
207
|
+
printHitMiss: () => console.log(`calls: ${memoizedWithMissHit.calls}
|
|
208
|
+
hit: ${memoizedWithMissHit.hit}
|
|
209
|
+
miss: ${memoizedWithMissHit.miss}
|
|
210
|
+
`)
|
|
211
|
+
});
|
|
212
|
+
const getter = memoizedWithMissHit.cache.get.bind(memoized.cache);
|
|
213
|
+
memoizedWithMissHit.cache.get = (key) => {
|
|
214
|
+
memoizedWithMissHit.calls++;
|
|
215
|
+
memoizedWithMissHit.hit++;
|
|
216
|
+
return getter(key);
|
|
217
|
+
};
|
|
218
|
+
const setter = memoizedWithMissHit.cache.set.bind(memoizedWithMissHit.cache);
|
|
219
|
+
memoizedWithMissHit.cache.set = (key, value) => {
|
|
220
|
+
memoizedWithMissHit.calls++;
|
|
221
|
+
memoizedWithMissHit.miss++;
|
|
222
|
+
return setter(key, value);
|
|
223
|
+
};
|
|
224
|
+
return memoizedWithMissHit;
|
|
225
|
+
}
|
|
226
|
+
function getLayerByName(layerName) {
|
|
227
|
+
const layer = _(layers).flatten().find({ name: layerName });
|
|
228
|
+
if (!layer) {
|
|
229
|
+
throw new Error(`Cannot find layer ${layerName}`);
|
|
230
|
+
}
|
|
231
|
+
return layer;
|
|
232
|
+
}
|
|
233
|
+
function validateEntryPointLayer(entryPoint) {
|
|
234
|
+
if (!entryPoint.getDependencyAPIs || !entryPoint.layer || _.isEmpty(layers)) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const highestLevelDependencies = _.chain(entryPoint.getDependencyAPIs())
|
|
238
|
+
.flatMap(apiKey => apiKey.layer
|
|
239
|
+
? _(apiKey.layer)
|
|
240
|
+
.castArray()
|
|
241
|
+
.map(l => ({
|
|
242
|
+
layer: getLayerByName(l),
|
|
243
|
+
apiKey
|
|
244
|
+
}))
|
|
245
|
+
.value()
|
|
246
|
+
: { apiKey })
|
|
247
|
+
.groupBy(dependency => { var _a; return (_a = dependency === null || dependency === void 0 ? void 0 : dependency.layer) === null || _a === void 0 ? void 0 : _a.dimension; })
|
|
248
|
+
.map(dimension => _.maxBy(dimension, dependency => ((dependency === null || dependency === void 0 ? void 0 : dependency.layer) ? dependency.layer.level : -Infinity)))
|
|
249
|
+
.value();
|
|
250
|
+
const currentLayers = _(entryPoint.layer)
|
|
251
|
+
.castArray()
|
|
252
|
+
.map(l => getLayerByName(l))
|
|
253
|
+
.value();
|
|
254
|
+
const getCurrentLayerOfSameDimension = (layer) => {
|
|
255
|
+
return currentLayers.find(entryPointLayer => entryPointLayer.dimension === layer.dimension);
|
|
256
|
+
};
|
|
257
|
+
highestLevelDependencies.forEach(highestLevelDependency => {
|
|
258
|
+
const currentLayer = (highestLevelDependency === null || highestLevelDependency === void 0 ? void 0 : highestLevelDependency.layer) && getCurrentLayerOfSameDimension(highestLevelDependency.layer);
|
|
259
|
+
if ((highestLevelDependency === null || highestLevelDependency === void 0 ? void 0 : highestLevelDependency.layer) && currentLayer && currentLayer.level < highestLevelDependency.layer.level) {
|
|
260
|
+
throw new Error(`Entry point ${entryPoint.name} of layer ${currentLayer.name} cannot depend on API ${slotKeyToName(highestLevelDependency.apiKey)} of layer ${highestLevelDependency.layer.name}`);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
function validateLayers(entryPoints) {
|
|
265
|
+
_.forEach(entryPoints, ep => validateEntryPointLayer(ep));
|
|
266
|
+
}
|
|
267
|
+
function addShells(entryPointsOrPackages) {
|
|
268
|
+
host.log.log('debug', `Adding ${entryPointsOrPackages.length} packages.`);
|
|
269
|
+
const entryPoints = _.flatten(entryPointsOrPackages);
|
|
270
|
+
const existingEntryPoints = Object.values(addedShells).map(shell => shell.entryPoint);
|
|
271
|
+
const allEntryPoints = existingEntryPoints.concat(unReadyEntryPointsStore.get(), entryPoints);
|
|
272
|
+
if (!options.disableLayersValidation) {
|
|
273
|
+
validateLayers(entryPoints);
|
|
274
|
+
}
|
|
275
|
+
validateUniqueShellNames(entryPoints);
|
|
276
|
+
!options.disableCheckCircularDependencies && !options.experimentalCyclicMode && validateCircularDependency(allEntryPoints);
|
|
277
|
+
const [lazyEntryPointsList, readyEntryPointsList] = _.partition(entryPoints, isLazyEntryPointDescriptor);
|
|
278
|
+
executeInstallShell(readyEntryPointsList);
|
|
279
|
+
lazyEntryPointsList.forEach(registerLazyEntryPoint);
|
|
280
|
+
setInstalledShellNames(getInstalledShellNames().concat(_.map(lazyEntryPointsList, 'name')));
|
|
281
|
+
return Promise.resolve();
|
|
282
|
+
}
|
|
283
|
+
function isAllAPIDependenciesAreReadyOrPending(checkedKey, pendingEntryPoints, passed = []) {
|
|
284
|
+
// TODO: Avoid iterating N (cycle length) times for the same cycle
|
|
285
|
+
const declarers = pendingEntryPoints.flatMap(ep => { var _a; return (((_a = ep.declareAPIs) === null || _a === void 0 ? void 0 : _a.call(ep)) || []).map(k => [k, ep]); });
|
|
286
|
+
const [, keyDeclarerEntryPoint] = declarers.find(([k, ep]) => _.isEqual(k, checkedKey)) || [];
|
|
287
|
+
if (!keyDeclarerEntryPoint) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
const dependencies = keyDeclarerEntryPoint.getDependencyAPIs && keyDeclarerEntryPoint.getDependencyAPIs();
|
|
291
|
+
const uncheckDependencies = _.differenceWith(dependencies, passed, _.isEqual);
|
|
292
|
+
const everyDependenciesReadyOrPending = _.every(uncheckDependencies, k => readyAPIs.has(getOwnSlotKey(k)) || isAllAPIDependenciesAreReadyOrPending(k, pendingEntryPoints, passed.concat(checkedKey)));
|
|
293
|
+
return everyDependenciesReadyOrPending;
|
|
294
|
+
}
|
|
295
|
+
function onInstallShellsEnd() {
|
|
296
|
+
const callbacks = entryPointsInstallationEndCallbacks.values();
|
|
297
|
+
try {
|
|
298
|
+
for (const callback of callbacks) {
|
|
299
|
+
callback();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
finally {
|
|
303
|
+
entryPointsInstallationEndCallbacks.clear();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function executeInstallShell(entryPoints) {
|
|
307
|
+
const [readyEntryPoints, currentUnReadyEntryPoints] = _.partition(entryPoints, entryPoint => {
|
|
308
|
+
const dependencies = entryPoint.getDependencyAPIs && entryPoint.getDependencyAPIs();
|
|
309
|
+
return _.every(dependencies, k => readyAPIs.has(getOwnSlotKey(k)) ||
|
|
310
|
+
(options.experimentalCyclicMode && isAllAPIDependenciesAreReadyOrPending(k, entryPoints)));
|
|
311
|
+
});
|
|
312
|
+
unReadyEntryPointsStore.set(_.union(_.difference(unReadyEntryPointsStore.get(), readyEntryPoints), currentUnReadyEntryPoints));
|
|
313
|
+
if (store && _.isEmpty(readyEntryPoints)) {
|
|
314
|
+
onInstallShellsEnd();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const shells = readyEntryPoints.map(createShell);
|
|
318
|
+
executeReadyEntryPoints(shells);
|
|
319
|
+
}
|
|
320
|
+
function executeReadyEntryPoints(shells) {
|
|
321
|
+
batchDeclarationsChangedCallbacks(() => {
|
|
322
|
+
isInstallingEntryPoints = true;
|
|
323
|
+
try {
|
|
324
|
+
invokeEntryPointPhase('getDependencyAPIs', shells, f => f.entryPoint.getDependencyAPIs && f.setDependencyAPIs(f.entryPoint.getDependencyAPIs()), f => !!f.entryPoint.getDependencyAPIs);
|
|
325
|
+
invokeEntryPointPhase('attach', shells, f => f.entryPoint.attach && f.entryPoint.attach(f), f => !!f.entryPoint.attach);
|
|
326
|
+
buildStore();
|
|
327
|
+
shells.forEach(f => f.setLifecycleState(true, true, false));
|
|
328
|
+
invokeEntryPointPhase('extend', shells, f => f.entryPoint.extend && f.entryPoint.extend(f), f => !!f.entryPoint.extend);
|
|
329
|
+
shells.forEach(f => {
|
|
330
|
+
addedShells.set(f.entryPoint.name, f);
|
|
331
|
+
f.setLifecycleState(true, true, true);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
isInstallingEntryPoints = false;
|
|
336
|
+
}
|
|
337
|
+
executeInstallShell(unReadyEntryPointsStore.get());
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
function executeShellsChangedCallbacks() {
|
|
341
|
+
shellsChangedCallbacks.forEach(f => f(_.keys(InstalledShellsSelectors.getInstalledShellsSet(getStore().getState()))));
|
|
342
|
+
}
|
|
343
|
+
function executeDeclarationsChangedCallbacks() {
|
|
344
|
+
declarationsChangedCallbacks.forEach(f => f());
|
|
345
|
+
}
|
|
346
|
+
function batchDeclarationsChangedCallbacks(action) {
|
|
347
|
+
if (isBatchingDeclarationsChangedCallbacks) {
|
|
348
|
+
return action();
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
isBatchingDeclarationsChangedCallbacks = true;
|
|
352
|
+
const result = action();
|
|
353
|
+
executeDeclarationsChangedCallbacks();
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
finally {
|
|
357
|
+
isBatchingDeclarationsChangedCallbacks = false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function setInstalledShellNames(names) {
|
|
361
|
+
const updates = toShellToggleSet(names, true);
|
|
362
|
+
getStore().dispatch(InstalledShellsActions.updateInstalledShells(updates));
|
|
363
|
+
executeShellsChangedCallbacks();
|
|
364
|
+
}
|
|
365
|
+
function setUninstalledShellNames(names) {
|
|
366
|
+
const updates = toShellToggleSet(names, false);
|
|
367
|
+
getStore().dispatch(InstalledShellsActions.updateInstalledShells(updates));
|
|
368
|
+
executeShellsChangedCallbacks();
|
|
369
|
+
}
|
|
370
|
+
function onDeclarationsChanged(callback) {
|
|
371
|
+
const callbackId = _.uniqueId('declarations-changed-callback-');
|
|
372
|
+
declarationsChangedCallbacks.set(callbackId, callback);
|
|
373
|
+
return () => {
|
|
374
|
+
declarationsChangedCallbacks.delete(callbackId);
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function onShellsChanged(callback) {
|
|
378
|
+
const callbackId = _.uniqueId('shells-changed-callback-');
|
|
379
|
+
shellsChangedCallbacks.set(callbackId, callback);
|
|
380
|
+
return callbackId;
|
|
381
|
+
}
|
|
382
|
+
function removeShellsChangedCallback(callbackId) {
|
|
383
|
+
shellsChangedCallbacks.delete(callbackId);
|
|
384
|
+
}
|
|
385
|
+
function declareSlot(key, declaringShell) {
|
|
386
|
+
const newSlot = registerSlotOrThrow(key, () => createExtensionSlot(key, host, declaringShell));
|
|
387
|
+
return newSlot;
|
|
388
|
+
}
|
|
389
|
+
function declareCustomSlot(key, handler, declaringShell) {
|
|
390
|
+
const newSlot = registerSlotOrThrow(key, () => createCustomExtensionSlot(key, handler, host, declaringShell));
|
|
391
|
+
return newSlot;
|
|
392
|
+
}
|
|
393
|
+
function slotKeyToName(key) {
|
|
394
|
+
return key.version === undefined ? key.name : `${key.name}(v${key.version})`;
|
|
395
|
+
}
|
|
396
|
+
function registerSlotOrThrow(key, factory) {
|
|
397
|
+
const slotName = slotKeyToName(key);
|
|
398
|
+
if (!extensionSlots.has(key) && !slotKeysByName.has(slotName)) {
|
|
399
|
+
const newSlot = factory();
|
|
400
|
+
extensionSlots.set(key, newSlot);
|
|
401
|
+
slotKeysByName.set(slotName, key);
|
|
402
|
+
return newSlot;
|
|
403
|
+
}
|
|
404
|
+
throw new Error(`Extension slot with key '${slotName}' already exists.`);
|
|
405
|
+
}
|
|
406
|
+
function getSlot(key) {
|
|
407
|
+
const ownKey = getOwnSlotKey(key);
|
|
408
|
+
const anySlot = extensionSlots.get(ownKey);
|
|
409
|
+
if (anySlot) {
|
|
410
|
+
return anySlot;
|
|
411
|
+
}
|
|
412
|
+
throw new Error(`Extension slot with key '${slotKeyToName(key)}' doesn't exist.`);
|
|
413
|
+
}
|
|
414
|
+
function hasSlot(key) {
|
|
415
|
+
const ownKey = getOwnSlotKey(key);
|
|
416
|
+
return extensionSlots.has(ownKey);
|
|
417
|
+
}
|
|
418
|
+
function tryGetAPI(key) {
|
|
419
|
+
if (!hasSlot(key)) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const APISlot = getSlot(key);
|
|
423
|
+
const item = APISlot.getSingleItem();
|
|
424
|
+
return item === null || item === void 0 ? void 0 : item.contribution;
|
|
425
|
+
}
|
|
426
|
+
function getAPI(key) {
|
|
427
|
+
const api = tryGetAPI(key);
|
|
428
|
+
if (!api) {
|
|
429
|
+
throw new Error(`API '${slotKeyToName(key)}' doesn't exist.`);
|
|
430
|
+
}
|
|
431
|
+
return api;
|
|
432
|
+
}
|
|
433
|
+
function hasAPI(key) {
|
|
434
|
+
return !!tryGetAPI(key);
|
|
435
|
+
}
|
|
436
|
+
function executeWhenFree(key, callback) {
|
|
437
|
+
if (isInstallingEntryPoints) {
|
|
438
|
+
entryPointsInstallationEndCallbacks.set(key, callback);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
callback();
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function getStore() {
|
|
445
|
+
if (store) {
|
|
446
|
+
return store;
|
|
447
|
+
}
|
|
448
|
+
throw new Error('Store was not yet created');
|
|
449
|
+
}
|
|
450
|
+
function getAllSlotKeys() {
|
|
451
|
+
return Array.from(extensionSlots.keys());
|
|
452
|
+
}
|
|
453
|
+
function getAllEntryPoints() {
|
|
454
|
+
throw new Error('not implemented');
|
|
455
|
+
}
|
|
456
|
+
function hasShell(name) {
|
|
457
|
+
const installedShellsSet = InstalledShellsSelectors.getInstalledShellsSet(getStore().getState());
|
|
458
|
+
return installedShellsSet[name] === true;
|
|
459
|
+
}
|
|
460
|
+
function isLazyEntryPoint(name) {
|
|
461
|
+
return lazyShells.has(name);
|
|
462
|
+
}
|
|
463
|
+
function registerLazyEntryPoint(descriptor) {
|
|
464
|
+
lazyShells.set(descriptor.name, descriptor.factory);
|
|
465
|
+
}
|
|
466
|
+
function getOwnSlotKey(key) {
|
|
467
|
+
if (key.public === true) {
|
|
468
|
+
const ownKey = slotKeysByName.get(slotKeyToName(key));
|
|
469
|
+
if (ownKey && ownKey.public) {
|
|
470
|
+
return ownKey;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return key;
|
|
474
|
+
}
|
|
475
|
+
function validateUniqueShellNames(entryPoints) {
|
|
476
|
+
entryPoints.forEach(f => validateUniqueShellName(f.name));
|
|
477
|
+
}
|
|
478
|
+
function validateUniqueShellName(name) {
|
|
479
|
+
if (!uniqueShellNames.has(name)) {
|
|
480
|
+
uniqueShellNames.add(name);
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
throw new Error(`Shell named '${name}' already exists`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function validateCircularDependency(entryPoints) {
|
|
487
|
+
const allDeclaredAPIs = new Map();
|
|
488
|
+
for (const ep of entryPoints) {
|
|
489
|
+
const apis = declaredAPIs(ep);
|
|
490
|
+
for (const api of apis) {
|
|
491
|
+
const existingDeclaration = allDeclaredAPIs.get(api.name);
|
|
492
|
+
if (existingDeclaration) {
|
|
493
|
+
host.log.log('warning', `The API: ${api.name} is declared in multiple endpoints: ${existingDeclaration.name} and ${ep.name}`);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
allDeclaredAPIs.set(api.name, ep);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
const graph = new Graph();
|
|
501
|
+
entryPoints.forEach(ep => {
|
|
502
|
+
const declaredApis = declaredAPIs(ep).map(x => slotKeyToName(x));
|
|
503
|
+
const dependencies = dependentAPIs(ep).map(x => slotKeyToName(x));
|
|
504
|
+
declaredApis.forEach(d => dependencies.forEach(y => graph.addConnection(d, y)));
|
|
505
|
+
});
|
|
506
|
+
const tarjan = new Tarjan(graph);
|
|
507
|
+
const sccs = tarjan.run();
|
|
508
|
+
for (const scc of sccs) {
|
|
509
|
+
if (scc.length > 1) {
|
|
510
|
+
const dependentGraph = {};
|
|
511
|
+
entryPoints.forEach(ep => {
|
|
512
|
+
const declaredApis = declaredAPIs(ep).map(child => child.name);
|
|
513
|
+
const dependencies = dependentAPIs(ep).map(child => child.name);
|
|
514
|
+
declaredApis.forEach(d => {
|
|
515
|
+
dependentGraph[d] = dependencies;
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
const circle = getCycle(dependentGraph);
|
|
519
|
+
if (circle) {
|
|
520
|
+
const reversedCircle = circle.reverse();
|
|
521
|
+
host.log.log('error', `Circular API dependency found: ${reversedCircle.join(' -> ')}`);
|
|
522
|
+
throw new Error(`Circular API dependency found`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
function buildStore() {
|
|
528
|
+
const contributedState = getSlot(stateSlotKey);
|
|
529
|
+
if (store) {
|
|
530
|
+
updateThrottledStore(host, store, contributedState);
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
store = createThrottledStore(host, contributedState, notifySubscribersIsRunning => {
|
|
534
|
+
isStoreSubscribersNotifyInProgress = notifySubscribersIsRunning;
|
|
535
|
+
}, notifyObserversIsRunning => {
|
|
536
|
+
isObserversNotifyInProgress = notifyObserversIsRunning;
|
|
537
|
+
}, updateShouldFlushMemoizationSync => {
|
|
538
|
+
shouldFlushMemoizationSync = updateShouldFlushMemoizationSync;
|
|
539
|
+
});
|
|
540
|
+
store.subscribe(() => {
|
|
541
|
+
if (shouldFlushMemoization) {
|
|
542
|
+
shouldFlushMemoization = false;
|
|
543
|
+
flushMemoizedForState();
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
store.syncSubscribe(() => {
|
|
547
|
+
shouldFlushMemoization = true;
|
|
548
|
+
if (isStoreSubscribersNotifyInProgress || isObserversNotifyInProgress || shouldFlushMemoizationSync) {
|
|
549
|
+
shouldFlushMemoization = false;
|
|
550
|
+
flushMemoizedForState();
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
return store;
|
|
555
|
+
}
|
|
556
|
+
function flushMemoizedForState() {
|
|
557
|
+
memoizedFunctions.forEach(({ f, shouldClear }) => {
|
|
558
|
+
if ((shouldClear || _.stubTrue)()) {
|
|
559
|
+
clearCache(f);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
function clearCache(memoizedFunction) {
|
|
564
|
+
if (memoizedFunction.cache && memoizedFunction.cache.clear) {
|
|
565
|
+
memoizedFunction.cache.clear();
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
function invokeEntryPointPhase(phase, // TODO: Exclude 'name'
|
|
569
|
+
shell, action, predicate) {
|
|
570
|
+
host.log.log('debug', `--- ${phase} phase ---`);
|
|
571
|
+
try {
|
|
572
|
+
shell.filter(f => !predicate || predicate(f)).forEach(f => invokeShell(f, action, phase));
|
|
573
|
+
}
|
|
574
|
+
catch (err) {
|
|
575
|
+
console.error(`${phase} phase FAILED`, err);
|
|
576
|
+
throw err;
|
|
577
|
+
}
|
|
578
|
+
host.log.log('debug', `--- End of ${phase} phase ---`);
|
|
579
|
+
}
|
|
580
|
+
function invokeShell(shell, action, phase) {
|
|
581
|
+
host.log.log('debug', `${phase} : ${shell.entryPoint.name}`);
|
|
582
|
+
try {
|
|
583
|
+
action(shell);
|
|
584
|
+
}
|
|
585
|
+
catch (err) {
|
|
586
|
+
host.log.log('error', 'AppHost.shellFailed', err, {
|
|
587
|
+
shell: shell.name,
|
|
588
|
+
phase,
|
|
589
|
+
message: `Shell '${shell.name}' FAILED ${phase} phase`,
|
|
590
|
+
error: err
|
|
591
|
+
});
|
|
592
|
+
throw err;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
function getAPIContributor(key) {
|
|
596
|
+
const ownKey = getOwnSlotKey(key);
|
|
597
|
+
return extensionSlots.has(ownKey) ? _.get(getSlot(ownKey).getSingleItem(), 'shell') : undefined;
|
|
598
|
+
}
|
|
599
|
+
function doesExtensionItemBelongToShells(extensionItem, shellNames) {
|
|
600
|
+
return (_.includes(shellNames, extensionItem.shell.name) ||
|
|
601
|
+
_.some(_.invoke(extensionItem.shell.entryPoint, 'getDependencyAPIs'), APIKey => _.includes(shellNames, _.get(getAPIContributor(APIKey), 'name'))));
|
|
602
|
+
}
|
|
603
|
+
function discardSlotKey(key) {
|
|
604
|
+
const ownKey = getOwnSlotKey(key);
|
|
605
|
+
readyAPIs.delete(ownKey);
|
|
606
|
+
extensionSlots.delete(ownKey);
|
|
607
|
+
slotKeysByName.delete(slotKeyToName(ownKey));
|
|
608
|
+
host.log.log('debug', `-- Removed slot keys: ${slotKeyToName(ownKey)} --`);
|
|
609
|
+
}
|
|
610
|
+
function findDependantShells(entryShell) {
|
|
611
|
+
const cache = new Map();
|
|
612
|
+
const _findDependantShells = (declaringShell) => _([...addedShells.entries()])
|
|
613
|
+
.flatMap(([name, shell]) => {
|
|
614
|
+
var _a, _b;
|
|
615
|
+
const cachedValue = cache.get(name);
|
|
616
|
+
if (cachedValue) {
|
|
617
|
+
return cachedValue;
|
|
618
|
+
}
|
|
619
|
+
const dependencyAPIs = ((_b = (_a = shell.entryPoint) === null || _a === void 0 ? void 0 : _a.getDependencyAPIs) === null || _b === void 0 ? void 0 : _b.call(_a)) || [];
|
|
620
|
+
const isDependant = dependencyAPIs.some(key => { var _a; return ((_a = getAPIContributor(key)) === null || _a === void 0 ? void 0 : _a.name) === declaringShell.name; });
|
|
621
|
+
if (!isDependant) {
|
|
622
|
+
return [];
|
|
623
|
+
}
|
|
624
|
+
const dependencies = [shell, ..._findDependantShells(shell)];
|
|
625
|
+
cache.set(name, dependencies);
|
|
626
|
+
return dependencies;
|
|
627
|
+
})
|
|
628
|
+
.uniqBy('name')
|
|
629
|
+
.value();
|
|
630
|
+
return _findDependantShells(entryShell);
|
|
631
|
+
}
|
|
632
|
+
function isShellBeingDependantOnInGroup(declaringShell, shells) {
|
|
633
|
+
return !!shells.find(dependantShell => {
|
|
634
|
+
var _a, _b;
|
|
635
|
+
const dependencyAPIs = ((_b = (_a = dependantShell.entryPoint) === null || _a === void 0 ? void 0 : _a.getDependencyAPIs) === null || _b === void 0 ? void 0 : _b.call(_a)) || [];
|
|
636
|
+
return dependencyAPIs.find(key => { var _a; return ((_a = getAPIContributor(key)) === null || _a === void 0 ? void 0 : _a.name) === declaringShell.name; });
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
function executeDetachOnShellReadyForRemoval(shellsToBeDetached, originalRequestedRemovalNames) {
|
|
640
|
+
invokeEntryPointPhase('detach', shellsToBeDetached, f => _.invoke(f.entryPoint, 'detach', f));
|
|
641
|
+
const detachedShellsNames = shellsToBeDetached.map(({ name }) => name);
|
|
642
|
+
const slotKeysToDiscard = findContributedAPIs(detachedShellsNames).concat(findDeclaredSlotKeys(detachedShellsNames));
|
|
643
|
+
extensionSlots.forEach(extensionSlot => extensionSlot.discardBy(extensionItem => doesExtensionItemBelongToShells(extensionItem, detachedShellsNames)));
|
|
644
|
+
detachedShellsNames.forEach(name => {
|
|
645
|
+
var _a;
|
|
646
|
+
const isResultOfMissingDependency = !originalRequestedRemovalNames.includes(name);
|
|
647
|
+
if (isResultOfMissingDependency) {
|
|
648
|
+
const entryPoint = (_a = addedShells.get(name)) === null || _a === void 0 ? void 0 : _a.entryPoint;
|
|
649
|
+
entryPoint && unReadyEntryPointsStore.get().push(entryPoint);
|
|
650
|
+
}
|
|
651
|
+
addedShells.delete(name);
|
|
652
|
+
uniqueShellNames.delete(name);
|
|
653
|
+
});
|
|
654
|
+
slotKeysToDiscard.forEach(discardSlotKey);
|
|
655
|
+
host.log.log('debug', `Done uninstalling ${detachedShellsNames}`);
|
|
656
|
+
}
|
|
657
|
+
function executeUninstallShells(names) {
|
|
658
|
+
batchDeclarationsChangedCallbacks(() => {
|
|
659
|
+
host.log.log('debug', `-- Uninstalling ${names} --`);
|
|
660
|
+
const shellsCandidatesToBeDetached = _(names)
|
|
661
|
+
.map(name => addedShells.get(name))
|
|
662
|
+
.compact()
|
|
663
|
+
.flatMap(shell => [shell, ...findDependantShells(shell)])
|
|
664
|
+
.uniqBy('name')
|
|
665
|
+
.value();
|
|
666
|
+
let queue = shellsCandidatesToBeDetached;
|
|
667
|
+
while (!_.isEmpty(queue)) {
|
|
668
|
+
const shellsToBeDetached = queue.filter(ep => !isShellBeingDependantOnInGroup(ep, queue));
|
|
669
|
+
if (_.isEmpty(shellsToBeDetached)) {
|
|
670
|
+
throw new Error(`Some shells could not detach: ${queue.map(({ name }) => name).join()}`);
|
|
671
|
+
}
|
|
672
|
+
executeDetachOnShellReadyForRemoval(shellsToBeDetached, names);
|
|
673
|
+
queue = _.differenceBy(queue, shellsToBeDetached, 'name');
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
function findContributedAPIs(shellNames) {
|
|
678
|
+
return [...readyAPIs].filter(APIKey => _.includes(shellNames, _.get(getAPIContributor(APIKey), 'name')));
|
|
679
|
+
}
|
|
680
|
+
function findDeclaredSlotKeys(shellNames) {
|
|
681
|
+
const shellNameSet = new Set(shellNames);
|
|
682
|
+
const result = [];
|
|
683
|
+
for (const entry of extensionSlots.entries()) {
|
|
684
|
+
const { declaringShell } = entry[1];
|
|
685
|
+
if (declaringShell && shellNameSet.has(declaringShell.name)) {
|
|
686
|
+
result.push(entry[0]);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return result;
|
|
690
|
+
}
|
|
691
|
+
function getInstalledShellNames() {
|
|
692
|
+
return [...addedShells].map(([v]) => v);
|
|
693
|
+
}
|
|
694
|
+
function removeShells(names) {
|
|
695
|
+
const shellNames = getInstalledShellNames();
|
|
696
|
+
executeUninstallShells(names);
|
|
697
|
+
setUninstalledShellNames(_.difference(shellNames, getInstalledShellNames()));
|
|
698
|
+
return Promise.resolve();
|
|
699
|
+
}
|
|
700
|
+
function createShell(entryPoint) {
|
|
701
|
+
let storeEnabled = false;
|
|
702
|
+
let APIsEnabled = false;
|
|
703
|
+
let wasInitCompleted = false;
|
|
704
|
+
let dependencyAPIs = new Set();
|
|
705
|
+
let nextObservableId = 1;
|
|
706
|
+
const boundaryAspects = [];
|
|
707
|
+
function isOwnContributedAPI(key) {
|
|
708
|
+
return getAPIContributor(key) === shell;
|
|
709
|
+
}
|
|
710
|
+
const shell = {
|
|
711
|
+
name: entryPoint.name,
|
|
712
|
+
entryPoint,
|
|
713
|
+
getSlot(key) {
|
|
714
|
+
const slot = host.getSlot(key);
|
|
715
|
+
const { declaringShell } = slot;
|
|
716
|
+
if (!declaringShell || declaringShell !== shell) {
|
|
717
|
+
throw new Error(`Shell '${shell.name}' is trying to get slot '${slotKeyToName(key)}' that is owned by '${declaringShell ? declaringShell.name : 'Host'}'`);
|
|
718
|
+
}
|
|
719
|
+
return slot;
|
|
720
|
+
},
|
|
721
|
+
hasSlot(key) {
|
|
722
|
+
if (hasSlot(key)) {
|
|
723
|
+
const slot = host.getSlot(key);
|
|
724
|
+
const { declaringShell } = slot;
|
|
725
|
+
return !!declaringShell && declaringShell === shell;
|
|
726
|
+
}
|
|
727
|
+
return false;
|
|
728
|
+
},
|
|
729
|
+
getAllSlotKeys: host.getAllSlotKeys,
|
|
730
|
+
getAllEntryPoints: host.getAllEntryPoints,
|
|
731
|
+
hasShell: host.hasShell,
|
|
732
|
+
isLazyEntryPoint: host.isLazyEntryPoint,
|
|
733
|
+
onShellsChanged: host.onShellsChanged,
|
|
734
|
+
onDeclarationsChanged: host.onDeclarationsChanged,
|
|
735
|
+
removeShellsChangedCallback: host.removeShellsChangedCallback,
|
|
736
|
+
declareSlot(key) {
|
|
737
|
+
return declareSlot(key, shell);
|
|
738
|
+
},
|
|
739
|
+
declareCustomSlot(key, handler) {
|
|
740
|
+
return declareCustomSlot(key, handler, shell);
|
|
741
|
+
},
|
|
742
|
+
setLifecycleState(enableStore, enableAPIs, initCompleted) {
|
|
743
|
+
storeEnabled = enableStore;
|
|
744
|
+
APIsEnabled = enableAPIs;
|
|
745
|
+
wasInitCompleted = initCompleted;
|
|
746
|
+
},
|
|
747
|
+
setDependencyAPIs(APIs) {
|
|
748
|
+
dependencyAPIs = new Set(APIs);
|
|
749
|
+
},
|
|
750
|
+
canUseAPIs() {
|
|
751
|
+
return APIsEnabled;
|
|
752
|
+
},
|
|
753
|
+
canUseStore() {
|
|
754
|
+
return storeEnabled;
|
|
755
|
+
},
|
|
756
|
+
wasInitializationCompleted() {
|
|
757
|
+
return wasInitCompleted;
|
|
758
|
+
},
|
|
759
|
+
runLateInitializer(initializer) {
|
|
760
|
+
const saveWasInitCompleted = wasInitCompleted;
|
|
761
|
+
try {
|
|
762
|
+
wasInitCompleted = false;
|
|
763
|
+
return initializer();
|
|
764
|
+
}
|
|
765
|
+
finally {
|
|
766
|
+
wasInitCompleted = saveWasInitCompleted;
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
addShells(entryPointsOrPackages) {
|
|
770
|
+
const shellNamesToBeinstalled = _.flatten(entryPointsOrPackages).map(x => x.name);
|
|
771
|
+
const shellNamesInstalledByCurrentEntryPoint = shellInstallers.get(shell) || [];
|
|
772
|
+
shellInstallers.set(shell, [...shellNamesInstalledByCurrentEntryPoint, ...shellNamesToBeinstalled]);
|
|
773
|
+
return host.addShells(entryPointsOrPackages);
|
|
774
|
+
},
|
|
775
|
+
removeShells(names) {
|
|
776
|
+
const namesInstalledByCurrentEntryPoint = shellInstallers.get(shell) || [];
|
|
777
|
+
const namesNotInstalledByCurrentEntryPoint = _.difference(names, namesInstalledByCurrentEntryPoint);
|
|
778
|
+
// TODO: Allow entry point to uninstall its own shell ?
|
|
779
|
+
if (!_.isEmpty(namesNotInstalledByCurrentEntryPoint)) {
|
|
780
|
+
throw new Error(`Shell ${entryPoint.name} is trying to uninstall shells: ${names} which is are not installed by entry point ${entryPoint.name} - This is not allowed`);
|
|
781
|
+
}
|
|
782
|
+
shellInstallers.set(shell, _.without(namesInstalledByCurrentEntryPoint, ...names));
|
|
783
|
+
return host.removeShells(names);
|
|
784
|
+
},
|
|
785
|
+
getAPI(key) {
|
|
786
|
+
if (dependencyAPIs.has(key) || isOwnContributedAPI(key)) {
|
|
787
|
+
return host.getAPI(key);
|
|
788
|
+
}
|
|
789
|
+
throw new Error(`API '${slotKeyToName(key)}' is not declared as dependency by entry point '${entryPoint.name}' (forgot to return it from getDependencyAPIs?)`);
|
|
790
|
+
},
|
|
791
|
+
hasAPI(key) {
|
|
792
|
+
return (dependencyAPIs.has(key) || isOwnContributedAPI(key)) && host.hasAPI(key);
|
|
793
|
+
},
|
|
794
|
+
contributeAPI(key, factory, apiOptions) {
|
|
795
|
+
host.log.log('debug', `Contributing API ${slotKeyToName(key)}.`);
|
|
796
|
+
if (!_.includes(_.invoke(entryPoint, 'declareAPIs') || [], key)) {
|
|
797
|
+
throw new Error(`Entry point '${entryPoint.name}' is trying to contribute API '${slotKeyToName(key)}' which it didn't declare`);
|
|
798
|
+
}
|
|
799
|
+
const areSameLayers = (l1, l2) => _.isEqual(_(l1).castArray().sort().value(), _(l2).castArray().sort().value());
|
|
800
|
+
if (!options.disableLayersValidation && (entryPoint.layer || key.layer) && !areSameLayers(entryPoint.layer, key.layer)) {
|
|
801
|
+
throw new Error(`Cannot contribute API ${slotKeyToName(key)} of layer ${key.layer || '<BLANK>'} from entry point ${entryPoint.name} of layer ${entryPoint.layer || '<BLANK>'}`);
|
|
802
|
+
}
|
|
803
|
+
const api = factory();
|
|
804
|
+
const monitoredAPI = monitorAPI(shell, options, normalizeApiName(slotKeyToName(key)), api /*, trace, memoizedArr*/, apiOptions);
|
|
805
|
+
const apiSlot = declareSlot(key);
|
|
806
|
+
APILayers.set(key, !options.disableLayersValidation && entryPoint.layer
|
|
807
|
+
? _(entryPoint.layer)
|
|
808
|
+
.castArray()
|
|
809
|
+
.map(l => getLayerByName(l))
|
|
810
|
+
.value()
|
|
811
|
+
: undefined);
|
|
812
|
+
apiSlot.contribute(shell, monitoredAPI);
|
|
813
|
+
readyAPIs.add(key);
|
|
814
|
+
if (!isInstallingEntryPoints) {
|
|
815
|
+
const shellNames = _.map(unReadyEntryPointsStore.get(), 'name');
|
|
816
|
+
executeInstallShell(unReadyEntryPointsStore.get());
|
|
817
|
+
setInstalledShellNames(_.difference(shellNames, _.map(unReadyEntryPointsStore.get(), 'name')));
|
|
818
|
+
}
|
|
819
|
+
return monitoredAPI;
|
|
820
|
+
},
|
|
821
|
+
contributeState(contributor) {
|
|
822
|
+
const contribution = {
|
|
823
|
+
notificationScope: 'broadcasting',
|
|
824
|
+
reducerFactory: contributor
|
|
825
|
+
};
|
|
826
|
+
getSlot(stateSlotKey).contribute(shell, contribution);
|
|
827
|
+
},
|
|
828
|
+
contributeObservableState(contributor, mapStateToSelectors) {
|
|
829
|
+
const observableUniqueName = `${entryPoint.name}/observable_${nextObservableId++}`;
|
|
830
|
+
const observable = createObservable(shell, observableUniqueName, mapStateToSelectors);
|
|
831
|
+
observable.subscribe(shell, () => {
|
|
832
|
+
flushMemoizedForState();
|
|
833
|
+
});
|
|
834
|
+
const protectedObservable = {
|
|
835
|
+
subscribe: observable.subscribe,
|
|
836
|
+
current: (allowUnsafeReading) => {
|
|
837
|
+
if (isStoreSubscribersNotifyInProgress && !allowUnsafeReading) {
|
|
838
|
+
throw new Error(`Observer created by ${shell.name} current() function: ` +
|
|
839
|
+
'Should not read observable value during subscribers notify. ' +
|
|
840
|
+
'If you wish to read the value, you component should be observing the value directly ' +
|
|
841
|
+
'(using observeWithShell or connectWithShellAndObserve)');
|
|
842
|
+
}
|
|
843
|
+
return observable.current();
|
|
844
|
+
},
|
|
845
|
+
notify: observable.notify
|
|
846
|
+
};
|
|
847
|
+
const contribution = {
|
|
848
|
+
notificationScope: 'observable',
|
|
849
|
+
reducerFactory: contributor,
|
|
850
|
+
observable
|
|
851
|
+
};
|
|
852
|
+
getSlot(stateSlotKey).contribute(shell, contribution);
|
|
853
|
+
return protectedObservable;
|
|
854
|
+
},
|
|
855
|
+
getStore() {
|
|
856
|
+
return {
|
|
857
|
+
dispatch: host.getStore().dispatchWithShell(shell),
|
|
858
|
+
subscribe: host.getStore().subscribe,
|
|
859
|
+
getState: () => {
|
|
860
|
+
const entireStoreState = host.getStore().getState();
|
|
861
|
+
return entireStoreState[shell.name];
|
|
862
|
+
},
|
|
863
|
+
flush: host.getStore().flush,
|
|
864
|
+
hasPendingSubscribers: host.getStore().hasPendingSubscribers,
|
|
865
|
+
deferSubscriberNotifications: host.getStore().deferSubscriberNotifications
|
|
866
|
+
};
|
|
867
|
+
},
|
|
868
|
+
contributeMainView(fromShell, contributor) {
|
|
869
|
+
getSlot(mainViewSlotKey).contribute(fromShell, contributor);
|
|
870
|
+
},
|
|
871
|
+
contributeBoundaryAspect(component) {
|
|
872
|
+
boundaryAspects.push(component);
|
|
873
|
+
},
|
|
874
|
+
memoizeForState(func, resolver, shouldClear) {
|
|
875
|
+
const memoized = memoize(func, resolver);
|
|
876
|
+
memoizedFunctions.set(memoized, shouldClear ? { f: memoized, shouldClear } : { f: memoized });
|
|
877
|
+
return memoized;
|
|
878
|
+
},
|
|
879
|
+
flushMemoizedForState,
|
|
880
|
+
memoize(func, resolver) {
|
|
881
|
+
return memoize(func, resolver);
|
|
882
|
+
},
|
|
883
|
+
clearCache,
|
|
884
|
+
getBoundaryAspects() {
|
|
885
|
+
return boundaryAspects;
|
|
886
|
+
},
|
|
887
|
+
getHostOptions: () => host.options,
|
|
888
|
+
log: createShellLogger(host, entryPoint),
|
|
889
|
+
[INTERNAL_DONT_USE_SHELL_GET_APP_HOST]: () => host,
|
|
890
|
+
lazyEvaluator
|
|
891
|
+
};
|
|
892
|
+
return shell;
|
|
893
|
+
}
|
|
894
|
+
function normalizeApiName(name) {
|
|
895
|
+
return name.charAt(0).toLowerCase() + name.substring(1).replace(new RegExp(' ', 'g'), '');
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
//# sourceMappingURL=appHost.js.map
|