Skip to content

Commit

Permalink
Make settings code resilient + refactoring (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
GCHQDeveloper81 authored Jul 22, 2024
1 parent dee1f2d commit 4c68686
Show file tree
Hide file tree
Showing 16 changed files with 127 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test+deploy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Install, test and Deploy LD Explorer

name: Test and Deploy
name: LD-Explorer

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# How to contributing
# How To Contribute

## Raising issues

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ld-explorer",
"version": "0.1.0",
"version": "0.1.1",
"private": true,
"license": "Apache-2.0",
"bugs": {
Expand Down
5 changes: 3 additions & 2 deletions scripts/add-copyright.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/bin/sh

copyright_notice="(c) Crown Copyright GCHQ"
folders="./src ./e2e ./test"

# Typescript files
for i in $(find ./src ./e2e ./test -name '*.ts');
for i in $(find $folders -name '*.ts');
do
if ! grep -q "$copyright_notice" $i
then
Expand All @@ -13,7 +14,7 @@ do
done

# Svelte files (note the different comment structure)
for i in $(find ./src ./e2e ./test -name '*.svelte');
for i in $(find $folders -name '*.svelte');
do
if ! grep -q "$copyright_notice" $i
then
Expand Down
4 changes: 2 additions & 2 deletions scripts/check-copyright.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/bin/sh

copyright_notice="Crown Copyright GCHQ"
missing=0

for i in $(find ./src ./e2e ./test -name '*.ts' -o -name '*.svelte');
do
if ! grep -q "Crown Copyright GCHQ" $i
if ! grep -q "$copyright_notice" $i
then
echo "Missing copyright notice in $i"
missing=$((missing + 1))
Expand Down
23 changes: 0 additions & 23 deletions src/lib/stores/localStorage.store.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* (c) Crown Copyright GCHQ */

import { createLocalStorageStore } from './localStorage.store';
import { createLocalStorageJSONStore } from './localStorageJson.store';
import { get } from 'svelte/store';
import { namespace } from '$lib/constants';

Expand All @@ -11,15 +11,15 @@ const exampleDefault = {
setting__baz: true
};

describe('localStorage store', () => {
let store: ReturnType<typeof createLocalStorageStore<typeof exampleDefault>>;
describe('localStorageJson store', () => {
let store: ReturnType<typeof createLocalStorageJSONStore<typeof exampleDefault>>;

beforeEach(() => {
localStorage.clear();
store = createLocalStorageStore(exampleKey, exampleDefault);
store = createLocalStorageJSONStore(exampleKey, exampleDefault);
});

describe(createLocalStorageStore, () => {
describe(createLocalStorageJSONStore, () => {
it('Creates a store with a default value', () => {
expect(get(store)).toStrictEqual(exampleDefault);
});
Expand Down
29 changes: 29 additions & 0 deletions src/lib/stores/localStorageJson.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* (c) Crown Copyright GCHQ */

import { retrieveJSONObject, storeJSONObject } from '$lib/util/localStorage.utils';
import { namespace } from '$lib/constants';
import { writable } from 'svelte/store';

/**
*
* @param key storage key to use
* @param defaultValue value to use if no value exists already
* @returns
*/
export function createLocalStorageJSONStore<T>(key: string, defaultValue: T) {
const namespacedKey = `${namespace}${key}`;

const { set, subscribe, update } = writable<T>(retrieveJSONObject(namespacedKey) || defaultValue);

subscribe((store) => {
storeJSONObject<T>(namespacedKey, store);
});

return {
restore() {
set(defaultValue);
},
subscribe,
update
};
}
4 changes: 2 additions & 2 deletions src/lib/stores/prefixes.store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* (c) Crown Copyright GCHQ */

import { createLocalStorageStore } from './localStorage.store';
import { createLocalStorageJSONStore } from './localStorageJson.store';
import defaultPrefixes from '$lib/data/prefixes.json';

export const prefixes = createLocalStorageStore('prefixes', defaultPrefixes);
export const prefixes = createLocalStorageJSONStore('prefixes', defaultPrefixes);
4 changes: 2 additions & 2 deletions src/lib/stores/settings.store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* (c) Crown Copyright GCHQ */

import { createLocalStorageStore } from './localStorage.store';
import { createLocalStorageJSONStore } from './localStorageJson.store';

interface GeneralSettings {
general__defaultLimit: number;
Expand All @@ -23,4 +23,4 @@ const defaultSettings: Settings = {
term__showLanguageTag: true
};

export const settings = createLocalStorageStore('settings', defaultSettings);
export const settings = createLocalStorageJSONStore('settings', defaultSettings);
46 changes: 46 additions & 0 deletions src/lib/util/localStorage.utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* (c) Crown Copyright GCHQ */

import { retrieveJSONObject, storeJSONObject } from './localStorage.utils';

const exampleObject = {
foo: 'bar',
fizz: 2,
bang: true
};

describe('localStorage functionality', () => {
afterEach(() => {
localStorage.clear();
});

describe(storeJSONObject, () => {
it('Sets an object on localStorage with a given key', () => {
storeJSONObject('test', exampleObject);
expect(JSON.parse(localStorage.getItem('test') || '""')).toStrictEqual(exampleObject);
});
});

describe(retrieveJSONObject, () => {
it('Returns an object from a given key of localStorage', () => {
localStorage.setItem('test', JSON.stringify(exampleObject));
expect(retrieveJSONObject('test')).toStrictEqual(exampleObject);
});

it('Fails gracefully upon encoutering corrupt storage items', () => {
// Arrange
const consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
localStorage.setItem('test', 'this is not valid JSON');

// Act
const storedValue = retrieveJSONObject('test');

// Assert
expect(consoleWarn).toHaveBeenCalledOnce();
expect(storedValue).toStrictEqual({});
});

it('Returns null if localStorage does not contain a given key', () => {
expect(retrieveJSONObject('test')).toBeNull();
});
});
});
33 changes: 33 additions & 0 deletions src/lib/util/localStorage.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* (c) Crown Copyright GCHQ */

/**
* Utilities related to any interactions with the browser's localStorage API.
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
*/

/**
* Set a key in local storage to contain an object. No-op if a non-JSON
* value is passed in.
* @param key
* @param value
*/
export function storeJSONObject<T>(key: string, value: T) {
localStorage.setItem(key, JSON.stringify(value));
}

/**
* Get a key from local storage and parse it as JSON. If for some reason the
* local storage is corrupt, an empty object is returned.
* @param key
* @returns value from store, parsed
*/
export function retrieveJSONObject(key: string) {
const value = localStorage.getItem(key);

try {
return value && JSON.parse(value);
} catch (e) {
console.warn('Unable to read value from local storage.', e);
return {};
}
}
33 changes: 0 additions & 33 deletions src/lib/util/storage.utils.test.ts

This file was deleted.

25 changes: 0 additions & 25 deletions src/lib/util/storage.utils.ts

This file was deleted.

0 comments on commit 4c68686

Please sign in to comment.