@data-client/rest
Version:
Quickly define typed REST resources and endpoints
77 lines (69 loc) • 2.11 kB
text/typescript
import {
compile,
PathFunction,
parse,
pathToRegexp,
Token,
ParamData,
} from './pathToRegexp.js';
import { ShortenPath } from './pathTypes.js';
const urlBaseCache: Record<string, PathFunction<object>> = Object.create(null);
export function getUrlBase(path: string): PathFunction<ParamData> {
if (!(path in urlBaseCache)) {
urlBaseCache[path] = compile(path);
}
return urlBaseCache[path];
}
const urlTokensCache: Record<string, Set<string>> = Object.create(null);
export function getUrlTokens(path: string): Set<string> {
if (!(path in urlTokensCache)) {
urlTokensCache[path] = tokenMap(parse(path).tokens);
}
return urlTokensCache[path];
}
const pathRegexCache: Record<string, RegExp> = Object.create(null);
export function getPathRegex(path: string): RegExp {
if (!(path in pathRegexCache)) {
pathRegexCache[path] = pathToRegexp(path).regexp;
}
return pathRegexCache[path];
}
function tokenMap(tokens: Token[]): Set<string> {
const tokenNames = new Set<string>();
for (const token of tokens) {
switch (token.type) {
case 'param':
case 'wildcard':
tokenNames.add(token.name);
break;
case 'group':
for (const name of tokenMap(token.tokens)) {
tokenNames.add(name);
}
break;
}
}
return tokenNames;
}
const proto = Object.prototype;
const gpo = Object.getPrototypeOf;
export function isPojo(obj: unknown): obj is Record<string, any> {
if (obj === null || typeof obj !== 'object') {
return false;
}
return gpo(obj) === proto;
}
export function shortenPath<S extends string>(path: S): ShortenPath<S> {
const lastTokenIndex = Math.max(path.lastIndexOf(':'), path.lastIndexOf('*'));
if (lastTokenIndex === -1)
throw new Error(
'Resource path requires at least one :parameter or *wildcard',
);
let shortUrlRoot: ShortenPath<S> = path.substring(0, lastTokenIndex) as any;
if (shortUrlRoot[shortUrlRoot.length - 1] === '/')
shortUrlRoot = shortUrlRoot.substring(
0,
shortUrlRoot.length - 1,
) as ShortenPath<S>;
return shortUrlRoot;
}