Files
FrenoCorp/node_modules/@solidjs/router/dist/utils.js
Michael Freno 7c684a42cc FRE-600: Fix code review blockers
- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 00:08:01 -04:00

186 lines
6.3 KiB
JavaScript

import { createMemo, getOwner, runWithOwner } from "solid-js";
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
const trimPathRegex = /^\/+|(\/)\/+$/g;
export const mockBase = "http://sr";
export function normalizePath(path, omitSlash = false) {
const s = path.replace(trimPathRegex, "$1");
return s ? (omitSlash || /^[?#]/.test(s) ? s : "/" + s) : "";
}
export function resolvePath(base, path, from) {
if (hasSchemeRegex.test(path)) {
return undefined;
}
const basePath = normalizePath(base);
const fromPath = from && normalizePath(from);
let result = "";
if (!fromPath || path.startsWith("/")) {
result = basePath;
}
else if (fromPath.toLowerCase().indexOf(basePath.toLowerCase()) !== 0) {
result = basePath + fromPath;
}
else {
result = fromPath;
}
return (result || "/") + normalizePath(path, !result);
}
export function invariant(value, message) {
if (value == null) {
throw new Error(message);
}
return value;
}
export function joinPaths(from, to) {
return normalizePath(from).replace(/\/*(\*.*)?$/g, "") + normalizePath(to);
}
export function extractSearchParams(url) {
const params = {};
url.searchParams.forEach((value, key) => {
if (key in params) {
if (Array.isArray(params[key]))
params[key].push(value);
else
params[key] = [params[key], value];
}
else
params[key] = value;
});
return params;
}
export function createMatcher(path, partial, matchFilters) {
const [pattern, splat] = path.split("/*", 2);
const segments = pattern.split("/").filter(Boolean);
const len = segments.length;
return (location) => {
const locSegments = location.split("/").filter(Boolean);
const lenDiff = locSegments.length - len;
if (lenDiff < 0 || (lenDiff > 0 && splat === undefined && !partial)) {
return null;
}
const match = {
path: len ? "" : "/",
params: {}
};
const matchFilter = (s) => matchFilters === undefined ? undefined : matchFilters[s];
for (let i = 0; i < len; i++) {
const segment = segments[i];
const dynamic = segment[0] === ":";
const locSegment = dynamic ? locSegments[i] : locSegments[i].toLowerCase();
const key = dynamic ? segment.slice(1) : segment.toLowerCase();
if (dynamic && matchSegment(locSegment, matchFilter(key))) {
match.params[key] = locSegment;
}
else if (dynamic || !matchSegment(locSegment, key)) {
return null;
}
match.path += `/${locSegment}`;
}
if (splat) {
const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
if (matchSegment(remainder, matchFilter(splat))) {
match.params[splat] = remainder;
}
else {
return null;
}
}
return match;
};
}
function matchSegment(input, filter) {
const isEqual = (s) => s === input;
if (filter === undefined) {
return true;
}
else if (typeof filter === "string") {
return isEqual(filter);
}
else if (typeof filter === "function") {
return filter(input);
}
else if (Array.isArray(filter)) {
return filter.some(isEqual);
}
else if (filter instanceof RegExp) {
return filter.test(input);
}
return false;
}
export function scoreRoute(route) {
const [pattern, splat] = route.pattern.split("/*", 2);
const segments = pattern.split("/").filter(Boolean);
return segments.reduce((score, segment) => score + (segment.startsWith(":") ? 2 : 3), segments.length - (splat === undefined ? 0 : 1));
}
export function createMemoObject(fn) {
const map = new Map();
const owner = getOwner();
return new Proxy({}, {
get(_, property) {
if (!map.has(property)) {
runWithOwner(owner, () => map.set(property, createMemo(() => fn()[property])));
}
return map.get(property)();
},
getOwnPropertyDescriptor() {
return {
enumerable: true,
configurable: true
};
},
ownKeys() {
return Reflect.ownKeys(fn());
},
has(_, property) {
return property in fn();
}
});
}
export function mergeSearchString(search, params) {
const merged = new URLSearchParams(search);
Object.entries(params).forEach(([key, value]) => {
if (value == null || value === "" || (value instanceof Array && !value.length)) {
merged.delete(key);
}
else {
if (value instanceof Array) {
// Delete all instances of the key before appending
merged.delete(key);
value.forEach(v => {
merged.append(key, String(v));
});
}
else {
merged.set(key, String(value));
}
}
});
const s = merged.toString();
return s ? `?${s}` : "";
}
export function expandOptionals(pattern) {
let match = /(\/?\:[^\/]+)\?/.exec(pattern);
if (!match)
return [pattern];
let prefix = pattern.slice(0, match.index);
let suffix = pattern.slice(match.index + match[0].length);
const prefixes = [prefix, (prefix += match[1])];
// This section handles adjacent optional params. We don't actually want all permuations since
// that will lead to equivalent routes which have the same number of params. For example
// `/:a?/:b?/:c`? only has the unique expansion: `/`, `/:a`, `/:a/:b`, `/:a/:b/:c` and we can
// discard `/:b`, `/:c`, `/:b/:c` by building them up in order and not recursing. This also helps
// ensure predictability where earlier params have precidence.
while ((match = /^(\/\:[^\/]+)\?/.exec(suffix))) {
prefixes.push((prefix += match[1]));
suffix = suffix.slice(match[0].length);
}
return expandOptionals(suffix).reduce((results, expansion) => [...results, ...prefixes.map(p => p + expansion)], []);
}
export function setFunctionName(obj, value) {
Object.defineProperty(obj, "name", {
value,
writable: false,
configurable: false
});
return obj;
}