]> git.codecow.com Git - libnemo.git/commitdiff
Change assert to class to improve type-checking reliably.
authorChris Duncan <chris@zoso.dev>
Sat, 6 Sep 2025 04:54:04 +0000 (21:54 -0700)
committerChris Duncan <chris@zoso.dev>
Sat, 6 Sep 2025 04:54:04 +0000 (21:54 -0700)
test/GLOBALS.mjs

index 2f718e5c348efbcfcf062ac9b18a234bf4639c6d..8388c0c746d9f402984665b5abeb84434a1b492e 100644 (file)
@@ -195,78 +195,108 @@ export const test = NodeTestTest != null
                }
        }
 
-export const assert = {
-       ok: (bool) => {
-               if (typeof bool !== 'boolean') {
-                       throw new Error('Invalid assertion')
-               }
-               if (!bool) {
-                       throw new Error(`test result falsy`, { cause: bool })
-               }
-               return true
-       },
-       exists: (a) => {
+export class assert {
+
+       /**
+        * @template T
+        * @param {T} a
+        * @returns {asserts a is NonNullable<T>}
+        */
+       static exists (a) {
                if (a == null) {
                        throw new Error(`argument is ${typeof a}`)
                }
-               return a != null
-       },
-       equal: (a, b) => {
+       }
+
+       /**
+        * @template T, U
+        * @param {(T | U)} a
+        * @param {U} b
+        * @returns {asserts a is U}
+        */
+       static equal (a, b) {
                if (a == null || b == null) {
                        throw new Error(`assert.equal() will not compare null or undefined`)
                }
                if (a !== b) {
                        throw new Error(`${a} not equal to ${b}`)
                }
-               return a === b
-       },
-       notEqual: (a, b) => {
+       }
+
+       /**
+        * @template T, U
+        * @param {(T | U)} a
+        * @param {U} b
+        * @returns {asserts a is NonNullable<T | U>}
+        */
+       static notEqual (a, b) {
                if (a == null || b == null) {
                        throw new Error(`assert.notEqual() will not compare null or undefined`)
                }
                if (a === b) {
                        throw new Error(`${a} equals ${b}`)
                }
-               return a !== b
-       },
-       nullish: (a) => {
+       }
+
+       /**
+        * @param {unknown} a
+        * @returns {asserts a is null | undefined}
+        */
+       static nullish (a) {
                if (a != null) {
                        const type = /^[aeiou]/i.test(typeof a) ? `an ${typeof a}` : `a ${typeof a}`
                        throw new Error(`argument exists and is ${type}`)
                }
-               return a == null
-       },
-       rejects: async (fn, msg) => {
+       }
+
+       /**
+        * @param {unknown} bool
+        * @returns {asserts bool}
+        */
+       static ok (bool) {
+               if (typeof bool !== 'boolean') {
+                       throw new Error('Invalid assertion')
+               }
+               if (!bool) {
+                       throw new Error(`test result falsy`, { cause: bool })
+               }
+       }
+
+       static async rejects (fn, msg) {
                if (fn.constructor.name === 'AsyncFunction') {
                        fn = fn()
                }
                if (fn instanceof Promise) {
                        try {
                                await fn
-                       } catch (err) {
-                               return true
-                       }
-                       throw new Error(msg ?? 'expected async function to reject')
+                               throw new Error(msg ?? 'expected async function to reject')
+                       } catch {}
                } else {
                        throw new Error(msg ?? 'expected async function')
                }
-       },
-       resolves: async (fn, msg) => {
+       }
+
+       static async resolves (fn, msg) {
                if (fn.constructor.name === 'AsyncFunction') {
                        fn = fn()
                }
                if (fn instanceof Promise) {
                        try {
                                await fn
-                               return true
                        } catch (err) {
                                throw new Error(msg ?? 'expected async function to resolve')
                        }
                } else {
                        throw new Error('expected async function')
                }
-       },
-       throws: (fn, msg) => {
+       }
+
+       /**
+        * @param {unknown} fn
+        * @param {any} msg
+        * @returns {asserts fn is Function}
+        */
+       static throws (fn, msg) {
                if (typeof fn !== 'function') {
                        throw new Error('expected function')
                }
@@ -275,9 +305,7 @@ export const assert = {
                }
                try {
                        fn()
-               } catch (err) {
-                       return true
-               }
-               throw new Error(msg ?? `expected function to throw an exception`)
+                       throw new Error(msg ?? `expected function to throw an exception`)
+               } catch {}
        }
 }