-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add pre-generated select options for activatable entries as cache
- Loading branch information
Showing
11 changed files
with
1,591 additions
and
44 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import { ValidResults } from "./main.js" | ||
|
||
export type CacheConfig<T> = { | ||
builder: (data: ValidResults) => T | ||
export type CacheConfig<T, D extends unknown[] = []> = { | ||
builder: (data: ValidResults, ...deps: D) => T | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,15 @@ | ||
import * as ActivatableSelectOptions from "../cache/activatableSelectOptions.js" | ||
import * as AncestorBloodAdvantages from "../cache/ancestorBloodAdvantages.js" | ||
import * as NewApplicationsAndUses from "../cache/newApplicationsAndUses.js" | ||
|
||
export type CacheMap = { | ||
activatableSelectOptions: ActivatableSelectOptions.ActivatableSelectOptionsCache | ||
ancestorBloodAdvantages: AncestorBloodAdvantages.AncestorBloodAdvantagesCache | ||
newApplicationsAndUses: NewApplicationsAndUses.NewApplicationsAndUsesCache | ||
} | ||
|
||
export const cacheMap = { | ||
activatableSelectOptions: ActivatableSelectOptions.config, | ||
ancestorBloodAdvantages: AncestorBloodAdvantages.config, | ||
newApplicationsAndUses: NewApplicationsAndUses.config, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import assert from "node:assert/strict" | ||
import { describe, it } from "node:test" | ||
import { | ||
isNotNullish, | ||
isNullish, | ||
mapNullable, | ||
mapNullableDefault, | ||
nullableToArray, | ||
} from "./nullable.js" | ||
|
||
describe("isNullish", () => { | ||
it("returns if a value is nullish", () => { | ||
assert.equal(isNullish(null), true) | ||
assert.equal(isNullish(undefined), true) | ||
assert.equal(isNullish(false), false) | ||
assert.equal(isNullish(0), false) | ||
assert.equal(isNullish(""), false) | ||
}) | ||
}) | ||
|
||
describe("isNotNullish", () => { | ||
it("returns if a value is not nullish", () => { | ||
assert.equal(isNotNullish(null), false) | ||
assert.equal(isNotNullish(undefined), false) | ||
assert.equal(isNotNullish(false), true) | ||
assert.equal(isNotNullish(0), true) | ||
assert.equal(isNotNullish(""), true) | ||
}) | ||
}) | ||
|
||
describe("mapNullable", () => { | ||
it("maps a value if it is not nullish", () => { | ||
assert.equal( | ||
mapNullable(2, x => x * 2), | ||
4 | ||
) | ||
}) | ||
|
||
it("returns the original value if it is nullish", () => { | ||
assert.equal( | ||
mapNullable(undefined, x => x * 2), | ||
undefined | ||
) | ||
}) | ||
}) | ||
|
||
describe("mapNullableDefault", () => { | ||
it("maps a value if it is not nullish", () => { | ||
assert.equal( | ||
mapNullableDefault(2, x => x * 2, 0), | ||
4 | ||
) | ||
}) | ||
|
||
it("returns a default if the value is nullish", () => { | ||
assert.equal( | ||
mapNullableDefault(undefined, x => x * 2, 0), | ||
0 | ||
) | ||
}) | ||
}) | ||
|
||
describe("nullableToArray", () => { | ||
it("wraps a non-nullish value into an array", () => { | ||
assert.deepEqual(nullableToArray(2), [2]) | ||
}) | ||
|
||
it("returns an empty array if the value is null or undefined", () => { | ||
assert.deepEqual(nullableToArray(undefined), []) | ||
assert.deepEqual(nullableToArray(null), []) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/** | ||
* Extracts `null` and `undefined` from a type. | ||
*/ | ||
export type Nullish<T = null | undefined> = T extends null | undefined ? T : never | ||
|
||
/** | ||
* Checks if a value is `null` or `undefined`. | ||
*/ | ||
export const isNullish = <T>(value: T): value is Exclude<T, NonNullable<T>> => | ||
value === null || value === undefined | ||
|
||
/** | ||
* Checks if a value is not `null` or `undefined`. | ||
*/ | ||
export const isNotNullish = <T>(value: T): value is NonNullable<T> => !isNullish(value) | ||
|
||
/** | ||
* Maps a value to another value if it is not `null` or `undefined`. | ||
*/ | ||
export const mapNullable = <T, U>(value: T, map: (value: NonNullable<T>) => U): U | Nullish<T> => | ||
isNotNullish(value) ? map(value) : (value as Nullish<T>) | ||
|
||
/** | ||
* Maps a value to another value if it is not `null` or `undefined`, otherwise | ||
* returns a default value. | ||
*/ | ||
export const mapNullableDefault = <T, U>( | ||
value: T, | ||
map: (value: NonNullable<T>) => U, | ||
defaultValue: U, | ||
): U => (isNotNullish(value) ? map(value) : defaultValue) | ||
|
||
/** | ||
* Returns an array, containing the value if it is not `null` or `undefined`. | ||
* | ||
* This can be useful in combination with the spread operator or | ||
* `Array.prototype.flatMap`. | ||
* @example | ||
* nullableToArray(2) // [2] | ||
* nullableToArray(undefined) // [] | ||
* | ||
* [...nullableToArray(2)] // [2] | ||
* [1, ...nullableToArray(2)] // [1, 2] | ||
* [1, ...nullableToArray(undefined)] // [1] | ||
*/ | ||
export const nullableToArray = <T>(value: T): NonNullable<T>[] => | ||
isNotNullish(value) ? [value] : [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import assert from "node:assert/strict" | ||
import { describe, it } from "node:test" | ||
import { mapObject } from "./object.js" | ||
|
||
describe("mapObject", () => { | ||
it("maps all own properties of an object to a new object", () => { | ||
const object = { a: 1, b: 2, c: 3 } | ||
const result = mapObject(object, (value, key) => value + key) | ||
assert.deepEqual(result, { a: "1a", b: "2b", c: "3c" }) | ||
}) | ||
|
||
it("omits properties for which the mapping function returns undefined", () => { | ||
const object = { a: 1, b: 2, c: 3 } | ||
const result = mapObject(object, (value, key) => (key === "b" ? undefined : value + key)) | ||
assert.deepEqual(result, { a: "1a", c: "3c" }) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* Maps all own properties of an object to a new object. Returning `undefined` | ||
* from the mapping function will omit the property from the result. | ||
*/ | ||
export const mapObject = <T extends object, U>( | ||
object: T, | ||
map: (value: T[keyof T], key: keyof T) => U | undefined | ||
): { [key in keyof T]: Exclude<U, undefined> } => { | ||
const result: { [key in keyof T]: Exclude<U, undefined> } = {} as never | ||
|
||
for (const key in object) { | ||
if (Object.hasOwn(object, key)) { | ||
const newValue = map(object[key], key) | ||
if (newValue !== undefined) { | ||
result[key] = newValue as Exclude<U, undefined> | ||
} | ||
} | ||
} | ||
|
||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import assert from "node:assert/strict" | ||
import { describe, it } from "node:test" | ||
import { assertExhaustive } from "./typeSafety.js" | ||
|
||
describe("assertExhaustive", () => { | ||
it("should throw an error with the message 'The switch is not exhaustive.'", () => { | ||
assert.throws( | ||
// @ts-expect-error The function should never receive a value. | ||
() => assertExhaustive(""), | ||
err => err instanceof Error && err.message === "The switch is not exhaustive." | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,16 @@ | ||
/** | ||
* This function is used to make sure that the `switch` is exhaustive. Place it | ||
* in the `default` case of the `switch`. | ||
* @param x The value that is used in the `switch`. | ||
* @param _x - The value that is used in the `switch`. | ||
* @example | ||
* const aorb = (x: "a" | "b") => { | ||
* switch (x) { | ||
* case "a": return 1 | ||
* case "b": return 2 | ||
* default: return assertExhaustive(x) | ||
* } | ||
* } | ||
*/ | ||
export function assertExhaustive(x: never): never { | ||
throw new Error("The switch is not exhaustive."); | ||
export function assertExhaustive(_x: never): never { | ||
throw new Error("The switch is not exhaustive.") | ||
} |
Oops, something went wrong.