@prass/botpress-native
Version:
A simple and powerful SDK for integrating Botpress Chat API with React Native,
116 lines (114 loc) • 4.57 kB
JavaScript
/**
* Utility class for constructing safe and consistent URLs.
* Ensures correct handling of leading/trailing slashes and prevents duplicate base URLs.
*/
class PrepareUrl {
/**
* Constructs a PrepareUrl instance.
*
* @param initialParts - Array of URL segments to form the base URL.
* @throws {Error} If initialParts is not an array.
* @throws {Error} If initialParts contain invalid URL structure.
*/
constructor(initialParts = []) {
this.baseUrl = null;
if (!Array.isArray(initialParts)) {
throw new TypeError("Initial parts must be an array of strings.");
}
if (initialParts.length > 0) {
this.baseUrl = this.cleanAndJoin(initialParts);
this.validateBaseUrl();
}
}
/**
* Cleans and joins URL parts by removing unnecessary slashes.
*
* @param parts - Array of URL segments.
* @returns A properly formatted URL string.
*/
cleanAndJoin(parts) {
return parts
.map((part) => {
if (typeof part !== "string") {
throw new TypeError("URL segments must be strings.");
}
return part.replace(/^\/+|\/+$/g, ""); // Remove leading/trailing slashes
})
.filter((part) => part !== "") // Remove empty segments
.join("/");
}
/**
* Validates that the base URL has a proper protocol (http or https).
*
* @throws {Error} If the base URL is invalid.
*/
validateBaseUrl() {
if (this.baseUrl && !/^https?:\/\//i.test(this.baseUrl)) {
throw new Error("Base URL must start with 'http://' or 'https://'.");
}
}
/**
* Generates a complete and safe URL with optional query parameters.
*
* If the base URL is not set, it initializes dynamically from the first `getUrl()` call.
* Prevents duplicate base URLs when segments include the base URL again.
*
* @param segments - Additional URL segments.
* @param queryParams - Optional query parameters object.
* @returns A well-formed URL string with query parameters (if provided).
* @throws {Error} If no base URL is set and segments do not form a valid URL.
*/
getUrl(segments, queryParams) {
// If no segments are provided, return the current base URL
if (!segments || segments.length === 0) {
return this.baseUrl || "";
}
// Validate segments
if (!Array.isArray(segments)) {
throw new TypeError("Segments must be an array of strings or numbers.");
}
const cleanedSegments = this.cleanAndJoin(segments.map(String));
// If baseUrl is not set, initialize it dynamically
if (!this.baseUrl) {
this.baseUrl = cleanedSegments;
this.validateBaseUrl();
return this.appendQueryParams(this.baseUrl, queryParams);
}
// Prevent duplicate base URLs
const baseParts = this.baseUrl.split("/");
const segmentParts = cleanedSegments.split("/");
let startIndex = 0;
while (startIndex < segmentParts.length &&
startIndex < baseParts.length &&
segmentParts[startIndex] === baseParts[startIndex]) {
startIndex++;
}
const uniquePath = segmentParts.slice(startIndex).join("/");
// Generate the final URL
const finalUrl = uniquePath
? `${this.baseUrl}/${uniquePath}`
: this.baseUrl;
return this.appendQueryParams(finalUrl, queryParams);
}
/**
* Appends query parameters to a URL if provided.
* Supports array values by repeating keys in the query string.
*
* @param url - The base URL to append query parameters to.
* @param queryParams - An object of key-value pairs to convert to query parameters.
* @returns The URL with query parameters appended.
*/
appendQueryParams(url, queryParams) {
if (queryParams && Object.keys(queryParams).length > 0) {
const queryString = Object.entries(queryParams)
.flatMap(([key, value]) => Array.isArray(value)
? value.map((v) => v && `${encodeURIComponent(key)}=${encodeURIComponent(v)}`)
: value && `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
return `${url}${queryString ? `?${queryString}` : ""}`;
}
return url;
}
}
export { PrepareUrl };
//# sourceMappingURL=prepareUrl.js.map