import _ from 'lodash' /** * Utilitaire permettant de construire une URL pour l'interrogation d'une API externe */ const UrlUtils = { /** * Concatenate a base url and a tail * @param base * @param tails * @private */ join(base: string | number, ...tails: Array): string { let url = String(base) tails.forEach((tail: string | number) => { url = url.replace(/^|\/$/g, '') + '/' + String(tail).replace(/^\/?|$/g, '') }) return url }, /** * Prepend the 'https://' part if neither 'http://' nor 'https://' prefixes are present, else does nothing * * @param url */ prependHttps(url: string): string { if (!url.match(/^https?:\/\/.*/)) { url = 'https://' + url } return url }, /** * Parse an URI to retrieve a parameter * * @param uri * @param parameter * @param default_ * @private */ getParameter( uri: string, parameter: string, default_: string | number | null = null, ): string | number | null { uri = this.prependHttps(uri) const urlParams = new URL(uri).searchParams let value: string | number | null = urlParams.get(parameter) if ( value && (default_ === null || Number.isInteger(default_)) && /^\d+$/.test(value) ) { // On convertit automatiquement si et seulement la valeur par défaut est elle-même un entier ou n'est pas définie value = parseInt(value) } return value ?? default_ }, /** * Extrait l'ID de l'URI passée en paramètre * L'URI est supposée être de la forme `.../foo/bar/{id}`, * où l'id est un identifiant numérique, à moins que `isLiteral` soit défini comme vrai. * Dans ce cas, si `isLiteral` est vrai, l'id sera retourné sous forme de texte. * * @param uri * @param isLiteral */ extractIdFromUri( uri: string, isLiteral: boolean = false, ): number | string | null { const partUri: Array = uri.split('/') const id: string = partUri.pop() ?? '' if (!id || (!isLiteral && !/\d+/.test(id))) { throw new Error('no id found') } return isLiteral ? id : parseInt(id) }, /** * Découpe une URI au niveau des '/' * Utilisé entre autres pour le breadcrumb * * Ex: * * foo/bar/1 => ['foo', 'bar', '1'] * /foo/bar/1 => ['foo', 'bar', '1'] * https://domain.com/foo/bar/1 => ['https:', 'domain.com', 'foo', 'bar', '1'] * * * @param uri */ split(uri: string) { return uri.split('/').filter((s) => s.length > 0) }, /** * Format and add a query to an url * If the url already has a query, append the new parameters to it. * If the query is an empty object, does nothing. * * Ex: * addQuery('foo/bar', {}) => 'foo/bar' * addQuery('foo/bar', {'a': 1}) => 'foo/bar?a=1' * addQuery('foo/bar?a=1', {'b': 2}) => 'foo/bar?a=1&b=2' * * @param url * @param query */ addQuery(url: string | URL, query: object): string { let urlObj = new URL(url, 'https://temporary-dommain.inexistent') as URL if (!_.isEmpty(query)) { urlObj = new URL( `${urlObj.origin}${urlObj.pathname}${urlObj.hash}?${new URLSearchParams( [ ...Array.from(urlObj.searchParams.entries()), ...Object.entries(query), ], )}`, ) } let result = urlObj.toString() if (urlObj.host === 'temporary-dommain.inexistent') { result = result.replace('https://temporary-dommain.inexistent', '') } return result }, /** * Make an ApiPlatform IRI for the given entity and id * * @see https://api-platform.com/docs/admin/handling-relations/ */ makeIRI(entity: string, id: number | string) { const initialId = id if (_.isString(id)) { id = parseInt(id) } if (!_.isFinite(id)) { throw new TypeError('Invalid id : ' + initialId) } return `/api/${entity}/${id}` }, } export default UrlUtils