Merge pull request #4725 from backstage/rugvip/globocon

core-api: new internal utility for accessing global singletons
This commit is contained in:
Patrik Oldsberg
2021-02-27 16:42:43 +01:00
committed by GitHub
3 changed files with 61 additions and 18 deletions
@@ -15,7 +15,7 @@
*/
import { ComponentType, ReactNode } from 'react';
import { globalObject } from '../lib/globalObject';
import { getGlobalSingleton } from '../lib/globalObject';
// TODO(Rugvip): Access via symbol is deprecated, remove once on 0.3.x
const DATA_KEY = Symbol('backstage-component-data');
@@ -32,22 +32,10 @@ type MaybeComponentNode = ReactNode & {
type?: ComponentType<any> & { [DATA_KEY]?: DataContainer };
};
const GLOBAL_KEY = '__@backstage/component-data-store__';
// The store is bridged across versions using the global object
function getStore() {
let storeObj = globalObject[GLOBAL_KEY] as
| { store: WeakMap<ComponentType<any>, DataContainer> }
| undefined;
if (!storeObj) {
const store = new WeakMap<ComponentType<any>, DataContainer>();
storeObj = { store };
globalObject[GLOBAL_KEY] = storeObj;
}
return storeObj.store;
}
const store = getStore();
const { store } = getGlobalSingleton('component-data-store', () => ({
store: new WeakMap<ComponentType<any>, DataContainer>(),
}));
export function attachComponentData<P>(
component: ComponentType<P>,
@@ -0,0 +1,42 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { getGlobalSingleton } from './globalObject';
const anyGlobal = global as any;
describe('getGlobalSingleton', () => {
beforeEach(() => {
delete anyGlobal['__@backstage/my-thing__'];
});
it('should return an existing value', () => {
const myThing = {};
anyGlobal['__@backstage/my-thing__'] = myThing;
expect(getGlobalSingleton('my-thing', () => ({}))).toBe(myThing);
expect(getGlobalSingleton('my-thing', () => ({}))).toBe(myThing);
});
it('should should create a new value', () => {
const myNewThing = {};
expect(anyGlobal['__@backstage/my-thing__']).toBe(undefined);
expect(getGlobalSingleton('my-thing', () => myNewThing)).toBe(myNewThing);
expect(anyGlobal['__@backstage/my-thing__']).toBe(myNewThing);
expect(getGlobalSingleton('my-thing', () => ({}))).toBe(myNewThing);
});
});
+15 -2
View File
@@ -15,7 +15,7 @@
*/
// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
function getGlobal() {
function getGlobalObject() {
if (typeof window !== 'undefined' && window.Math === Math) {
return window;
}
@@ -26,4 +26,17 @@ function getGlobal() {
return Function('return this')();
}
export const globalObject = getGlobal();
export const globalObject = getGlobalObject();
export function getGlobalSingleton<T>(id: string, supplier: () => T): T {
const key = `__@backstage/${id}__`;
let value = globalObject[key];
if (value) {
return value;
}
value = supplier();
globalObject[key] = value;
return value;
}