Refactoring: Split shared types into seperate modules and document alot.
This commit is contained in:
parent
e08ae944c4
commit
843cd37243
31 changed files with 2498 additions and 842 deletions
server/shared/utils
30
server/shared/utils/enums.ts
Normal file
30
server/shared/utils/enums.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Utility functions for enums.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper function to detect unhandled enum fields in `switch` statements at compile time. In case this function
|
||||
* is called at runtime anyway (which should not happen) it throws a runtime error.
|
||||
*
|
||||
* In the example below the compiler will complain if not for all fields of `Enum` a corresponding `case` statement
|
||||
* exists.
|
||||
*
|
||||
* @param field - Unhandled field, the value being switched over.
|
||||
* @throws {@link Error} - If the function is called at runtime.
|
||||
*
|
||||
* @example
|
||||
* switch (enumValue) {
|
||||
* case Enum.FIELD1:
|
||||
* return;
|
||||
* case Enum.FIELD2:
|
||||
* return;
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* default:
|
||||
* return unhandledEnumField(enumValue);
|
||||
* }
|
||||
*/
|
||||
export function unhandledEnumField(field: never): never {
|
||||
throw new Error(`Unhandled enum field: ${field}`);
|
||||
}
|
42
server/shared/utils/json.ts
Normal file
42
server/shared/utils/json.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Utility functions for JSON.
|
||||
*/
|
||||
import { isJSONValue, JSONObject, JSONValue } from "../types";
|
||||
|
||||
/**
|
||||
* Parses the given `string` and converts it into a {@link JSONValue}.
|
||||
*
|
||||
* For the string to be considered valid JSON it has to satisfy the requirements for {@link JSON.parse}.
|
||||
*
|
||||
* @param str - `string` to parse.
|
||||
* @returns The parsed integer JSON value.
|
||||
* @throws {@link SyntaxError} - If the given `string` does not represent a valid JSON value.
|
||||
*/
|
||||
export function parseJSON(str: string): JSONValue {
|
||||
const json = JSON.parse(str);
|
||||
if (!isJSONValue(json)) {
|
||||
throw new Error("Invalid JSON returned. Should never happen.");
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes `undefined` fields from the given JSON'ish object to make it a valid {@link JSONObject}.
|
||||
*
|
||||
* Note: This only happens for fields directly belonging to the given object. No recursive cleanup is performed.
|
||||
*
|
||||
* @param obj - Object to remove `undefined` fields from.
|
||||
* @returns Cleaned up JSON object.
|
||||
*/
|
||||
export function filterUndefinedFromJSON(obj: {
|
||||
[key: string]: JSONValue | undefined;
|
||||
}): JSONObject {
|
||||
const result: JSONObject = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (value !== undefined) {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
14
server/shared/utils/node.ts
Normal file
14
server/shared/utils/node.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Utility functions for node related data.
|
||||
*/
|
||||
import { MAC, MapId } from "../types";
|
||||
|
||||
/**
|
||||
* Converts the MAC address of a Freifunk node to an id representing it on the community's node map.
|
||||
*
|
||||
* @param mac - MAC address of the node
|
||||
* @returns ID of the node on the map
|
||||
*/
|
||||
export function mapIdFromMAC(mac: MAC): MapId {
|
||||
return mac.toLowerCase().replace(/:/g, "") as MapId;
|
||||
}
|
19
server/shared/utils/objects.ts
Normal file
19
server/shared/utils/objects.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Helper functions for objects.
|
||||
*/
|
||||
import { hasOwnProperty } from "../types";
|
||||
|
||||
/**
|
||||
* If the given value is an object this function returns the property specified by `key` if it exists.
|
||||
*
|
||||
* @param arg - Value to treat as an object to look up the property.
|
||||
* @param key - Key indexing the property.
|
||||
* @returns The property of the given object indexed by `key` or `undefined` if `arg` is not an object
|
||||
* or has no property `key`.
|
||||
*/
|
||||
export function getFieldIfExists(
|
||||
arg: unknown,
|
||||
key: PropertyKey
|
||||
): unknown | undefined {
|
||||
return hasOwnProperty(arg, key) ? arg[key] : undefined;
|
||||
}
|
|
@ -1,9 +1,29 @@
|
|||
import { isString, MAC } from "../types";
|
||||
/**
|
||||
* Utility functions all around strings.
|
||||
*/
|
||||
import { isInteger, MAC } from "../types";
|
||||
|
||||
/**
|
||||
* Trims the given `string` and replaces multiple whitespaces by one space each.
|
||||
*
|
||||
* Can be used to make sure user input has a canonical form.
|
||||
*
|
||||
* @param str - `string` to normalize.
|
||||
* @returns The normalized `string`.
|
||||
*/
|
||||
export function normalizeString(str: string): string {
|
||||
return isString(str) ? str.trim().replace(/\s+/g, " ") : str;
|
||||
return str.trim().replace(/\s+/g, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a {@link MAC} address so that it has a canonical format:
|
||||
*
|
||||
* The `MAC` address will be converted so that it is all uppercase with colon as the delimiter, e.g.:
|
||||
* `12:34:56:78:9A:BC`.
|
||||
*
|
||||
* @param mac - `MAC` address to normalize.
|
||||
* @returns The normalized `MAC` address.
|
||||
*/
|
||||
export function normalizeMac(mac: MAC): MAC {
|
||||
// parts only contains values at odd indexes
|
||||
const parts = mac
|
||||
|
@ -20,9 +40,26 @@ export function normalizeMac(mac: MAC): MAC {
|
|||
return macParts.join(":") as MAC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given `string` and converts it into an integer.
|
||||
*
|
||||
* For a `string` to be considered a valid representation of an integer `number` it has to satisfy the
|
||||
* following criteria:
|
||||
*
|
||||
* * The integer is base `10`.
|
||||
* * The `string` starts with an optional `+` or `-` sign followed by one or more digits.
|
||||
* * The first digit must not be `0`.
|
||||
* * The `string` does not contain any other characters.
|
||||
*
|
||||
* @param str - `string` to parse.
|
||||
* @returns The parsed integer `number`.
|
||||
* @throws {@link SyntaxError} - If the given `string` does not represent a valid integer.
|
||||
*/
|
||||
export function parseInteger(str: string): number {
|
||||
const parsed = parseInt(str, 10);
|
||||
if (parsed.toString() === str) {
|
||||
const original = str.startsWith("+") ? str.slice(1) : str;
|
||||
|
||||
if (isInteger(parsed) && parsed.toString() === original) {
|
||||
return parsed;
|
||||
} else {
|
||||
throw new SyntaxError(
|
||||
|
|
28
server/shared/utils/time.ts
Normal file
28
server/shared/utils/time.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Utility functions for "wibbly wobbly timey wimey" stuff.
|
||||
*/
|
||||
import { UnixTimestampMilliseconds, UnixTimestampSeconds } from "../types";
|
||||
|
||||
/**
|
||||
* Converts an {@link UnixTimestampMilliseconds} to an {@link UnixTimestampSeconds} rounding down.
|
||||
*
|
||||
* @param ms - The timestamp in milliseconds.
|
||||
* @returns - The timestamp in seconds.
|
||||
*/
|
||||
export function toUnixTimestampSeconds(
|
||||
ms: UnixTimestampMilliseconds
|
||||
): UnixTimestampSeconds {
|
||||
return Math.floor(ms / 1000) as UnixTimestampSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an {@link UnixTimestampSeconds} to an {@link UnixTimestampMilliseconds}.
|
||||
*
|
||||
* @param s - The timestamp in seconds.
|
||||
* @returns - The timestamp in milliseconds.
|
||||
*/
|
||||
export function toUnixTimestampMilliseconds(
|
||||
s: UnixTimestampSeconds
|
||||
): UnixTimestampMilliseconds {
|
||||
return (s * 1000) as UnixTimestampMilliseconds;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue