implement auto reconnect
This commit is contained in:
+60
-60
@@ -3,113 +3,113 @@ const ENCRYPTION_ALG = "AES-GCM";
|
||||
|
||||
// minimal
|
||||
export async function encryptString(
|
||||
plaintext: string,
|
||||
passphrase: string
|
||||
plaintext: string,
|
||||
passphrase: string,
|
||||
): Promise<string> {
|
||||
if (!window.crypto.subtle) return plaintext;
|
||||
if (!window.crypto.subtle) return plaintext;
|
||||
|
||||
const iv = generateIV();
|
||||
const key = await importKey(passphrase, "encrypt");
|
||||
const encryptedArray = await encrypt(iv, key, plaintext);
|
||||
const iv = generateIV();
|
||||
const key = await importKey(passphrase, "encrypt");
|
||||
const encryptedArray = await encrypt(iv, key, plaintext);
|
||||
|
||||
const encryptionData = {
|
||||
iv: uInt8ToArray(iv),
|
||||
encryptedArray: uInt8ToArray(encryptedArray),
|
||||
};
|
||||
return btoa(JSON.stringify(encryptionData));
|
||||
const encryptionData = {
|
||||
iv: uInt8ToArray(iv),
|
||||
encryptedArray: uInt8ToArray(encryptedArray),
|
||||
};
|
||||
return btoa(JSON.stringify(encryptionData));
|
||||
}
|
||||
|
||||
export async function decryptString(
|
||||
cyphertext: string,
|
||||
passphrase: string
|
||||
cyphertext: string,
|
||||
passphrase: string,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const encrypionData = JSON.parse(atob(cyphertext));
|
||||
const iv = arrayToUint8(encrypionData.iv);
|
||||
const encryptedArray = arrayToUint8(encrypionData.encryptedArray);
|
||||
try {
|
||||
const encrypionData = JSON.parse(atob(cyphertext));
|
||||
const iv = arrayToUint8(encrypionData.iv);
|
||||
const encryptedArray = arrayToUint8(encrypionData.encryptedArray);
|
||||
|
||||
const key = await importKey(passphrase, "decrypt");
|
||||
return await decrypt(iv, key, encryptedArray);
|
||||
} catch {
|
||||
return cyphertext;
|
||||
}
|
||||
const key = await importKey(passphrase, "decrypt");
|
||||
return await decrypt(iv, key, encryptedArray);
|
||||
} catch {
|
||||
return cyphertext;
|
||||
}
|
||||
}
|
||||
|
||||
// process
|
||||
export function encode(string: string): Uint8Array {
|
||||
return new TextEncoder().encode(string);
|
||||
return new TextEncoder().encode(string);
|
||||
}
|
||||
|
||||
export function decode(array: Uint8Array): string {
|
||||
return new TextDecoder("utf-8").decode(array);
|
||||
return new TextDecoder("utf-8").decode(array);
|
||||
}
|
||||
|
||||
export async function encrypt(
|
||||
iv: Uint8Array,
|
||||
key: CryptoKey,
|
||||
message: string
|
||||
iv: Uint8Array,
|
||||
key: CryptoKey,
|
||||
message: string,
|
||||
): Promise<Uint8Array> {
|
||||
const arrayBuffer = await window.crypto.subtle.encrypt(
|
||||
{ name: ENCRYPTION_ALG, iv },
|
||||
key,
|
||||
encode(message)
|
||||
);
|
||||
return new Uint8Array(arrayBuffer);
|
||||
const arrayBuffer = await window.crypto.subtle.encrypt(
|
||||
{ name: ENCRYPTION_ALG, iv },
|
||||
key,
|
||||
encode(message),
|
||||
);
|
||||
return new Uint8Array(arrayBuffer);
|
||||
}
|
||||
|
||||
export async function decrypt(
|
||||
iv: Uint8Array,
|
||||
key: CryptoKey,
|
||||
cyphertext: Uint8Array
|
||||
iv: Uint8Array,
|
||||
key: CryptoKey,
|
||||
cyphertext: Uint8Array,
|
||||
): Promise<string> {
|
||||
const arrayBuffer = await crypto.subtle.decrypt(
|
||||
{ name: ENCRYPTION_ALG, iv },
|
||||
key,
|
||||
cyphertext
|
||||
);
|
||||
return arrayBufferToString(arrayBuffer);
|
||||
const arrayBuffer = await crypto.subtle.decrypt(
|
||||
{ name: ENCRYPTION_ALG, iv },
|
||||
key,
|
||||
cyphertext,
|
||||
);
|
||||
return arrayBufferToString(arrayBuffer);
|
||||
}
|
||||
|
||||
export async function hash(encoded: Uint8Array): Promise<ArrayBuffer> {
|
||||
return await crypto.subtle.digest("SHA-256", encoded);
|
||||
return await crypto.subtle.digest("SHA-256", encoded);
|
||||
}
|
||||
|
||||
// iv
|
||||
export function generateIV(): Uint8Array {
|
||||
return crypto.getRandomValues(new Uint8Array(IV_SIZE));
|
||||
return crypto.getRandomValues(new Uint8Array(IV_SIZE));
|
||||
}
|
||||
|
||||
export function splitMergedString(mergedString: string): [Uint8Array, string] {
|
||||
const iv = mergedString.slice(0, IV_SIZE);
|
||||
const encryptedString = mergedString.slice(IV_SIZE);
|
||||
const iv = mergedString.slice(0, IV_SIZE);
|
||||
const encryptedString = mergedString.slice(IV_SIZE);
|
||||
|
||||
return [JSON.parse(iv), encryptedString];
|
||||
return [JSON.parse(iv), encryptedString];
|
||||
}
|
||||
|
||||
// key
|
||||
export async function importKey(
|
||||
passphrase: string,
|
||||
purpose: "encrypt" | "decrypt"
|
||||
passphrase: string,
|
||||
purpose: "encrypt" | "decrypt",
|
||||
): Promise<CryptoKey> {
|
||||
return await crypto.subtle.importKey(
|
||||
"raw",
|
||||
await hash(encode(passphrase)),
|
||||
{ name: ENCRYPTION_ALG },
|
||||
false,
|
||||
[purpose]
|
||||
);
|
||||
return await crypto.subtle.importKey(
|
||||
"raw",
|
||||
await hash(encode(passphrase)),
|
||||
{ name: ENCRYPTION_ALG },
|
||||
false,
|
||||
[purpose],
|
||||
);
|
||||
}
|
||||
|
||||
// conversion
|
||||
export function arrayBufferToString(arrayBuffer: ArrayBuffer): string {
|
||||
const uInt8Array = new Uint8Array(arrayBuffer);
|
||||
return decode(uInt8Array);
|
||||
const uInt8Array = new Uint8Array(arrayBuffer);
|
||||
return decode(uInt8Array);
|
||||
}
|
||||
|
||||
export function uInt8ToArray(uInt8Array: Uint8Array): number[] {
|
||||
return Array.from(uInt8Array);
|
||||
return Array.from(uInt8Array);
|
||||
}
|
||||
|
||||
export function arrayToUint8(array: number[]): Uint8Array {
|
||||
return new Uint8Array(array);
|
||||
return new Uint8Array(array);
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
export const DATA_VERSION = "v2";
|
||||
|
||||
export function checkIsValidObject(object: any): boolean {
|
||||
return object.dataVersion == DATA_VERSION;
|
||||
return object.dataVersion == DATA_VERSION;
|
||||
}
|
||||
|
||||
export function checkMatchesObjectStructure(
|
||||
objectToCheck: any,
|
||||
reference: any
|
||||
objectToCheck: any,
|
||||
reference: any,
|
||||
): boolean {
|
||||
if (typeof reference != "object") {
|
||||
return typeof objectToCheck == typeof reference;
|
||||
}
|
||||
|
||||
for (const key of Object.keys(reference)) {
|
||||
const requiredType = typeof reference[key];
|
||||
const actualType = typeof objectToCheck[key];
|
||||
if (requiredType != actualType) return false;
|
||||
|
||||
if (Array.isArray(reference[key]) || reference[key] instanceof Set) {
|
||||
// only check if array is not empty
|
||||
if (objectToCheck[key].length == 0) continue;
|
||||
if (objectToCheck[key].size == 0) continue;
|
||||
|
||||
// check first item of array
|
||||
const [firstOfObjectToCheck] = objectToCheck[key];
|
||||
const [fisrtOfReference] = reference[key];
|
||||
const doesFirstItemMatch = checkMatchesObjectStructure(
|
||||
firstOfObjectToCheck,
|
||||
fisrtOfReference
|
||||
);
|
||||
if (doesFirstItemMatch == false) return false;
|
||||
} else if (requiredType == "object") {
|
||||
// recurse into objects
|
||||
const doesNestedObjectMatch = checkMatchesObjectStructure(
|
||||
objectToCheck[key],
|
||||
reference[key]
|
||||
);
|
||||
if (doesNestedObjectMatch == false) return false;
|
||||
if (typeof reference != "object") {
|
||||
return typeof objectToCheck == typeof reference;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
for (const key of Object.keys(reference)) {
|
||||
const requiredType = typeof reference[key];
|
||||
const actualType = typeof objectToCheck[key];
|
||||
if (requiredType != actualType) return false;
|
||||
|
||||
if (Array.isArray(reference[key]) || reference[key] instanceof Set) {
|
||||
// only check if array is not empty
|
||||
if (objectToCheck[key].length == 0) continue;
|
||||
if (objectToCheck[key].size == 0) continue;
|
||||
|
||||
// check first item of array
|
||||
const [firstOfObjectToCheck] = objectToCheck[key];
|
||||
const [fisrtOfReference] = reference[key];
|
||||
const doesFirstItemMatch = checkMatchesObjectStructure(
|
||||
firstOfObjectToCheck,
|
||||
fisrtOfReference,
|
||||
);
|
||||
if (doesFirstItemMatch == false) return false;
|
||||
} else if (requiredType == "object") {
|
||||
// recurse into objects
|
||||
const doesNestedObjectMatch = checkMatchesObjectStructure(
|
||||
objectToCheck[key],
|
||||
reference[key],
|
||||
);
|
||||
if (doesNestedObjectMatch == false) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export interface ValidObject {
|
||||
dataVersion: "v2";
|
||||
dataVersion: "v2";
|
||||
}
|
||||
|
||||
+182
-181
@@ -1,277 +1,278 @@
|
||||
import { checkIsValidObject, checkMatchesObjectStructure } from "./typeSafety";
|
||||
|
||||
export interface Stringifiable {
|
||||
toString(): string;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
// crypto
|
||||
export function generateRandomToken(length: number): string {
|
||||
const array = new Uint8Array(length);
|
||||
crypto.getRandomValues(array);
|
||||
return array.join("");
|
||||
const array = new Uint8Array(length);
|
||||
crypto.getRandomValues(array);
|
||||
return array.join("");
|
||||
}
|
||||
|
||||
// date
|
||||
export function createTimestamp(): string {
|
||||
return new Date().toISOString();
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
// filters etc
|
||||
export type StringEntryObject = { [key: string]: Stringifiable | undefined };
|
||||
|
||||
export function filterObjectsByStringEntries<T>(
|
||||
reference: StringEntryObject,
|
||||
converter: (object: T) => StringEntryObject,
|
||||
objects: T[]
|
||||
reference: StringEntryObject,
|
||||
converter: (object: T) => StringEntryObject,
|
||||
objects: T[],
|
||||
): Set<T> {
|
||||
const matches: Set<T> = new Set();
|
||||
const matches: Set<T> = new Set();
|
||||
|
||||
object_loop: for (const object of objects) {
|
||||
const doesMatch: boolean = checkDoesObjectMatchReference(
|
||||
reference,
|
||||
converter(object)
|
||||
);
|
||||
if (doesMatch) matches.add(object);
|
||||
}
|
||||
object_loop: for (const object of objects) {
|
||||
const doesMatch: boolean = checkDoesObjectMatchReference(
|
||||
reference,
|
||||
converter(object),
|
||||
);
|
||||
if (doesMatch) matches.add(object);
|
||||
}
|
||||
|
||||
return matches;
|
||||
return matches;
|
||||
}
|
||||
|
||||
export function checkDoesObjectMatchReference(
|
||||
reference: StringEntryObject,
|
||||
stringEntryObject: StringEntryObject
|
||||
reference: StringEntryObject,
|
||||
stringEntryObject: StringEntryObject,
|
||||
): boolean {
|
||||
reference_entry_loop: for (const referenceEntry of Object.entries(
|
||||
reference
|
||||
)) {
|
||||
const [referenceKey, referenceValue] = referenceEntry;
|
||||
const stringEntryObjectValue: Stringifiable | undefined =
|
||||
stringEntryObject[referenceKey];
|
||||
reference_entry_loop: for (const referenceEntry of Object.entries(
|
||||
reference,
|
||||
)) {
|
||||
const [referenceKey, referenceValue] = referenceEntry;
|
||||
const stringEntryObjectValue: Stringifiable | undefined =
|
||||
stringEntryObject[referenceKey];
|
||||
|
||||
if (referenceValue == undefined) return false;
|
||||
if (referenceValue == undefined) return false;
|
||||
|
||||
if (referenceValue[0] == "-") {
|
||||
const strippedReferenceValue: string = referenceValue
|
||||
.toString()
|
||||
.substring(1);
|
||||
// property may not exist
|
||||
if (
|
||||
strippedReferenceValue == "" &&
|
||||
stringEntryObjectValue != undefined &&
|
||||
stringEntryObjectValue != ""
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (referenceValue[0] == "-") {
|
||||
const strippedReferenceValue: string = referenceValue
|
||||
.toString()
|
||||
.substring(1);
|
||||
// property may not exist
|
||||
if (
|
||||
strippedReferenceValue == "" &&
|
||||
stringEntryObjectValue != undefined &&
|
||||
stringEntryObjectValue != ""
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// property may not match
|
||||
if (stringEntryObjectValue == strippedReferenceValue) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// property must exist but be anything
|
||||
if (
|
||||
referenceValue == "" &&
|
||||
(stringEntryObjectValue == undefined || stringEntryObjectValue == "")
|
||||
) {
|
||||
return false;
|
||||
} else if (referenceValue == "") {
|
||||
continue reference_entry_loop;
|
||||
}
|
||||
// property may not match
|
||||
if (stringEntryObjectValue == strippedReferenceValue) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// property must exist but be anything
|
||||
if (
|
||||
referenceValue == "" &&
|
||||
(stringEntryObjectValue == undefined ||
|
||||
stringEntryObjectValue == "")
|
||||
) {
|
||||
return false;
|
||||
} else if (referenceValue == "") {
|
||||
continue reference_entry_loop;
|
||||
}
|
||||
|
||||
// property must match
|
||||
if (stringEntryObjectValue != referenceValue) {
|
||||
return false;
|
||||
}
|
||||
// property must match
|
||||
if (stringEntryObjectValue != referenceValue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function collectObjectValuesForKey<T>(
|
||||
key: string,
|
||||
converter: (object: T) => StringEntryObject,
|
||||
objects: T[]
|
||||
key: string,
|
||||
converter: (object: T) => StringEntryObject,
|
||||
objects: T[],
|
||||
): string[] {
|
||||
const values: Set<string> = new Set();
|
||||
const values: Set<string> = new Set();
|
||||
|
||||
for (const object of objects) {
|
||||
const stringEntryObject: StringEntryObject = converter(object);
|
||||
const stringEntryObjectValue: Stringifiable | undefined =
|
||||
stringEntryObject[key];
|
||||
if (stringEntryObjectValue == undefined || stringEntryObjectValue == "")
|
||||
continue;
|
||||
for (const object of objects) {
|
||||
const stringEntryObject: StringEntryObject = converter(object);
|
||||
const stringEntryObjectValue: Stringifiable | undefined =
|
||||
stringEntryObject[key];
|
||||
if (stringEntryObjectValue == undefined || stringEntryObjectValue == "")
|
||||
continue;
|
||||
|
||||
values.add(stringEntryObjectValue.toString());
|
||||
}
|
||||
values.add(stringEntryObjectValue.toString());
|
||||
}
|
||||
|
||||
return [...values.values()];
|
||||
return [...values.values()];
|
||||
}
|
||||
|
||||
export function filterObjectsByWords<T>(
|
||||
query: string,
|
||||
getStringsOfObject: (object: T) => string[],
|
||||
objects: T[]
|
||||
query: string,
|
||||
getStringsOfObject: (object: T) => string[],
|
||||
objects: T[],
|
||||
): Set<T> {
|
||||
const matches: Set<T> = new Set();
|
||||
const matches: Set<T> = new Set();
|
||||
|
||||
object_loop: for (const object of objects) {
|
||||
const doesMatch: boolean = checkDoesObjectMatchSearch(
|
||||
query,
|
||||
getStringsOfObject,
|
||||
object
|
||||
);
|
||||
if (doesMatch) matches.add(object);
|
||||
}
|
||||
object_loop: for (const object of objects) {
|
||||
const doesMatch: boolean = checkDoesObjectMatchSearch(
|
||||
query,
|
||||
getStringsOfObject,
|
||||
object,
|
||||
);
|
||||
if (doesMatch) matches.add(object);
|
||||
}
|
||||
|
||||
return matches;
|
||||
return matches;
|
||||
}
|
||||
|
||||
export function checkDoesObjectMatchSearch<T>(
|
||||
query: string,
|
||||
getStringsOfObject: (object: T) => string[],
|
||||
object: T
|
||||
query: string,
|
||||
getStringsOfObject: (object: T) => string[],
|
||||
object: T,
|
||||
): boolean {
|
||||
if (query == "") return true;
|
||||
if (query == "") return true;
|
||||
|
||||
const stringsInObject: string[] = getStringsOfObject(object);
|
||||
const wordsInObject: string[] = [];
|
||||
for (const string of stringsInObject) {
|
||||
const lowercaseWordsInString = string
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((word) => word != "");
|
||||
wordsInObject.push(...lowercaseWordsInString);
|
||||
}
|
||||
|
||||
const lowercaseWordsInQuery = query
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((word) => word != "");
|
||||
for (const queryWord of lowercaseWordsInQuery) {
|
||||
if (queryWord[0] == "-") {
|
||||
// exclusion
|
||||
const wordContent = queryWord.substring(1);
|
||||
if (wordsInObject.includes(wordContent)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (wordsInObject.includes(queryWord) == false) {
|
||||
return false;
|
||||
}
|
||||
const stringsInObject: string[] = getStringsOfObject(object);
|
||||
const wordsInObject: string[] = [];
|
||||
for (const string of stringsInObject) {
|
||||
const lowercaseWordsInString = string
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((word) => word != "");
|
||||
wordsInObject.push(...lowercaseWordsInString);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
const lowercaseWordsInQuery = query
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((word) => word != "");
|
||||
for (const queryWord of lowercaseWordsInQuery) {
|
||||
if (queryWord[0] == "-") {
|
||||
// exclusion
|
||||
const wordContent = queryWord.substring(1);
|
||||
if (wordsInObject.includes(wordContent)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (wordsInObject.includes(queryWord) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// handlers
|
||||
export type Handler<T> = (item: T) => void;
|
||||
|
||||
export class HandlerManager<T> {
|
||||
handlers: Set<Handler<T>> = new Set();
|
||||
handlers: Set<Handler<T>> = new Set();
|
||||
|
||||
// manage
|
||||
addHandler = (handler: Handler<T>): void => {
|
||||
this.handlers.add(handler);
|
||||
};
|
||||
// manage
|
||||
addHandler = (handler: Handler<T>): void => {
|
||||
this.handlers.add(handler);
|
||||
};
|
||||
|
||||
deleteHandler = (handler: Handler<T>): void => {
|
||||
this.handlers.delete(handler);
|
||||
};
|
||||
deleteHandler = (handler: Handler<T>): void => {
|
||||
this.handlers.delete(handler);
|
||||
};
|
||||
|
||||
// trigger
|
||||
trigger = (item: T): void => {
|
||||
for (const handler of this.handlers) {
|
||||
handler(item);
|
||||
}
|
||||
};
|
||||
// trigger
|
||||
trigger = (item: T): void => {
|
||||
for (const handler of this.handlers) {
|
||||
handler(item);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// sorting
|
||||
export class IndexManager<T> {
|
||||
private itemToString: (item: T) => string;
|
||||
private itemToString: (item: T) => string;
|
||||
|
||||
sortedStrings: string[] = [];
|
||||
sortedStrings: string[] = [];
|
||||
|
||||
// methods
|
||||
update = (items: T[]): void => {
|
||||
this.sortedStrings = [];
|
||||
// methods
|
||||
update = (items: T[]): void => {
|
||||
this.sortedStrings = [];
|
||||
|
||||
let strings: string[] = [];
|
||||
for (const item of items) {
|
||||
const string: string = this.itemToString(item);
|
||||
strings.push(string);
|
||||
let strings: string[] = [];
|
||||
for (const item of items) {
|
||||
const string: string = this.itemToString(item);
|
||||
strings.push(string);
|
||||
}
|
||||
|
||||
this.sortedStrings = strings.sort(localeCompare);
|
||||
};
|
||||
|
||||
getIndex = (item: T): number => {
|
||||
const string: string = this.itemToString(item);
|
||||
const index: number = this.sortedStrings.indexOf(string);
|
||||
return index;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(itemToString: (item: T) => string) {
|
||||
this.itemToString = itemToString;
|
||||
}
|
||||
|
||||
this.sortedStrings = strings.sort(localeCompare);
|
||||
};
|
||||
|
||||
getIndex = (item: T): number => {
|
||||
const string: string = this.itemToString(item);
|
||||
const index: number = this.sortedStrings.indexOf(string);
|
||||
return index;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(itemToString: (item: T) => string) {
|
||||
this.itemToString = itemToString;
|
||||
}
|
||||
}
|
||||
|
||||
// storage
|
||||
export function getLocalStorageItemAndClear(key: string): string | null {
|
||||
const value: string | null = localStorage.getItem(key);
|
||||
localStorage.removeItem(key);
|
||||
if (value != null) localStorage.setItem(`_${key}`, value);
|
||||
return value;
|
||||
const value: string | null = localStorage.getItem(key);
|
||||
localStorage.removeItem(key);
|
||||
if (value != null) localStorage.setItem(`_${key}`, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// string & parsing
|
||||
export function stringify(data: any): string {
|
||||
return JSON.stringify(data, null, 4);
|
||||
return JSON.stringify(data, null, 4);
|
||||
}
|
||||
|
||||
export function padZero(string: string | undefined, length: number): string {
|
||||
return (string ?? "").padStart(length, "0");
|
||||
return (string ?? "").padStart(length, "0");
|
||||
}
|
||||
|
||||
export function parse(string: string): any {
|
||||
try {
|
||||
return JSON.parse(string);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
return JSON.parse(string);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export function parseValidObject<T>(string: string, reference: T): T | null {
|
||||
const parsed: any = parse(string);
|
||||
if (checkIsValidObject(parsed) == false) return null;
|
||||
const parsed: any = parse(string);
|
||||
if (checkIsValidObject(parsed) == false) return null;
|
||||
|
||||
const doesMatchReference: boolean = checkMatchesObjectStructure(
|
||||
parsed,
|
||||
reference
|
||||
);
|
||||
if (doesMatchReference == false) return null;
|
||||
const doesMatchReference: boolean = checkMatchesObjectStructure(
|
||||
parsed,
|
||||
reference,
|
||||
);
|
||||
if (doesMatchReference == false) return null;
|
||||
|
||||
return parsed;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export function parseOrFallback(inputString: string): any {
|
||||
try {
|
||||
return JSON.parse(inputString);
|
||||
} catch {
|
||||
return inputString;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(inputString);
|
||||
} catch {
|
||||
return inputString;
|
||||
}
|
||||
}
|
||||
|
||||
export function parseArray(inputString: string): any[] {
|
||||
const parsed: any = parseOrFallback(inputString);
|
||||
if (Array.isArray(parsed) == false) return [];
|
||||
return parsed;
|
||||
const parsed: any = parseOrFallback(inputString);
|
||||
if (Array.isArray(parsed) == false) return [];
|
||||
return parsed;
|
||||
}
|
||||
|
||||
// sort
|
||||
export function localeCompare(a: string, b: string): number {
|
||||
return a.localeCompare(b);
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user