All files util.ts

100% Statements 71/71
100% Branches 37/37
100% Functions 7/7
100% Lines 71/71

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117  2x   2x 1129x 1129x 1128x 1126x 1126x 11x 1115x 1126x   1129x   2x 17321x 17321x 15405x   17321x               2x 217x 217x 217x 187x 187x   30x 30x   2x 260x 254x   2x 252x 260x 237x 237x   2x 7115x 7115x 7115x 7115x 6096x 5363x 5348x   7115x   2x   483x 215x 215x     463x 1x 1x     267x 267x     267x   267x 267x 267x                         2x 866x 866x 866x 866x 866x   546x 754x   351x   866x   130x   866x   64x   866x 1x 866x 866x  
import type { Route, RouteConfirmHookResult, RouteMatchType } from './types';
export const isBrowser = typeof window === 'object';
 
export function isNotNullish(value: unknown): boolean {
    return (
        value !== undefined &&
        value !== null &&
        !Number.isNaN(
            value instanceof Number
                ? value.valueOf() // For new Number() cases
                : value
        )
    );
}
 
export function isPlainObject(o: unknown): o is Record<string, any> {
    return (
        o?.constructor === Object ||
        Object.prototype.toString.call(o) === '[object Object]'
    );
}
 
/**
 * Check if value is a valid non-empty plain object
 * Only check enumerable string keys to ensure it's a proper plain object
 * @param value Value to check
 * @returns true if it's a valid non-empty plain object
 */
export function isNonEmptyPlainObject(
    value: unknown
): value is Record<string, any> {
    if (!isPlainObject(value)) {
        return false;
    }
    // Only check enumerable string keys to ensure valid properties of plain object
    return Object.keys(value as Record<string, any>).length > 0;
}
 
export const removeFromArray = <T>(arr: T[], ele: T) => {
    if (!Array.isArray(arr) || arr.length === 0) return;
    const i = Number.isNaN(ele)
        ? // If ele is NaN, use findIndex to search for NaN, because NaN !== NaN, so we can't use indexOf directly
          arr.findIndex((item) => Number.isNaN(item))
        : arr.indexOf(ele);
    if (i === -1) return;
    arr.splice(i, 1);
};
 
export function isValidConfirmHookResult(
    result: unknown
): result is Exclude<RouteConfirmHookResult, void> {
    return (
        result === false ||
        typeof result === 'function' ||
        typeof result === 'string' ||
        isPlainObject(result)
    );
}
 
export function isUrlEqual(url1: URL, url2?: URL | null): boolean {
    // If url2 doesn't exist, return false
    if (!url2) {
        return false;
    }
 
    // If it's the same object reference, return true directly
    if (url1 === url2) {
        return true;
    }
 
    // Copy and sort query parameters
    (url1 = new URL(url1)).searchParams.sort();
    (url2 = new URL(url2)).searchParams.sort();
    // Avoid trailing hash symbol impact from empty hash
    // biome-ignore lint/correctness/noSelfAssign:
    url1.hash = url1.hash;
    // biome-ignore lint/correctness/noSelfAssign:
    url2.hash = url2.hash;
    return url1.href === url2.href;
}
 
/**
 * Compare if two routes match
 *
 * @param route1 First route object
 * @param route2 Second route object, may be null
 * @param matchType Match type
 * - 'route': Route-level matching, compare if route configurations are the same
 * - 'exact': Exact matching, compare if full paths are the same
 * - 'include': Include matching, check if route1 path starts with route2 path
 * @returns Whether they match
 */
export function isRouteMatched(
    route1: Route,
    route2: Route | null,
    matchType: RouteMatchType
): boolean {
    if (!route2) return false;
 
    switch (matchType) {
        case 'route':
            // Route-level matching - compare route configurations
            return route1.config === route2.config;
 
        case 'exact':
            // Exact matching - full paths are identical
            return route1.fullPath === route2.fullPath;
 
        case 'include':
            // Include matching - route1 path contains route2 path
            return route1.fullPath.startsWith(route2.fullPath);
 
        default:
            return false;
    }
}