main
ts 77 lines 2.13 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import invariant from 'invariant';
9 import {
10 compressToEncodedURIComponent,
11 decompressFromEncodedURIComponent,
12 } from 'lz-string';
13 import {defaultStore, defaultConfig} from '../defaultStore';
14
15 /**
16 * Global Store for Playground
17 */
18 export interface Store {
19 source: string;
20 config: string;
21 showInternals: boolean;
22 }
23 export function encodeStore(store: Store): string {
24 return compressToEncodedURIComponent(JSON.stringify(store));
25 }
26 export function decodeStore(hash: string): any {
27 return JSON.parse(decompressFromEncodedURIComponent(hash));
28 }
29
30 /**
31 * Serialize, encode, and save @param store to localStorage and update URL.
32 */
33 export function saveStore(store: Store): void {
34 const hash = encodeStore(store);
35 localStorage.setItem('playgroundStore', hash);
36 history.replaceState({}, '', `#${hash}`);
37 }
38
39 /**
40 * Check if @param raw is a valid Store by if
41 * - it has a `source` property and is a string
42 */
43 function isValidStore(raw: unknown): raw is Store {
44 return (
45 raw != null &&
46 typeof raw == 'object' &&
47 'source' in raw &&
48 typeof raw['source'] === 'string'
49 );
50 }
51
52 /**
53 * Deserialize, decode, and initialize @param store from URL and then
54 * localStorage. Throw an error if Store is malformed.
55 */
56 export function initStoreFromUrlOrLocalStorage(): Store {
57 const encodedSourceFromUrl = location.hash.slice(1);
58 const encodedSourceFromLocal = localStorage.getItem('playgroundStore');
59 const encodedSource = encodedSourceFromUrl || encodedSourceFromLocal;
60
61 /**
62 * No data in the URL and no data in the localStorage to fallback to.
63 * Initialize with the default store.
64 */
65 if (!encodedSource) return defaultStore;
66
67 const raw: any = decodeStore(encodedSource);
68
69 invariant(isValidStore(raw), 'Invalid Store');
70
71 // Make sure all properties are populated
72 return {
73 source: raw.source,
74 config: 'config' in raw && raw['config'] ? raw.config : defaultConfig,
75 showInternals: 'showInternals' in raw ? raw.showInternals : false,
76 };
77 }