@shopify/shopify-api
Version:
Shopify API Library for Node - accelerate development with support for authentication, graphql proxy, webhooks
165 lines (156 loc) • 4.94 kB
text/typescript
import type {Headers} from './types';
/**
* Canonicalizes a header name by capitalizing each segment and ensuring consistent hyphenation.
*
* @param hdr - The header name to canonicalize.
* @returns The canonicalized header name.
*/
export function canonicalizeHeaderName(hdr: string): string {
return hdr.replace(
/(^|-)(\w+)/g,
(_fullMatch, start, letters) =>
start +
letters.slice(0, 1).toUpperCase() +
letters.slice(1).toLowerCase(),
);
}
/**
* Retrieves all values associated with a canonicalized header name from the headers object.
*
* @param headers - The headers object or undefined.
* @param needle_ - The header name to search for.
* @returns An array of header values associated with the canonicalized header name.
*/
export function getHeaders(
headers: Headers | undefined,
needle_: string,
): string[] {
const result: string[] = [];
if (!headers) return result;
const needle = canonicalizeHeaderName(needle_);
for (const [key, values] of Object.entries(headers)) {
if (canonicalizeHeaderName(key) !== needle) continue;
if (Array.isArray(values)) {
result.push(...values);
} else {
result.push(values);
}
}
return result;
}
/**
* Retrieves the first value associated with a canonicalized header name from the headers object.
*
* @param headers - The headers object or undefined.
* @param needle - The header name to search for.
* @returns The first value associated with the canonicalized header name, or undefined if not found.
*/
export function getHeader(
headers: Headers | undefined,
needle: string,
): string | undefined {
if (!headers) return undefined;
return getHeaders(headers, needle)?.[0];
}
/**
* Sets a header to a single value, canonicalizing the header name.
*
* @param headers - The headers object.
* @param key - The header name to set.
* @param value - The value to assign to the header.
*/
export function setHeader(headers: Headers, key: string, value: string) {
canonicalizeHeaders(headers);
headers[canonicalizeHeaderName(key)] = [value];
}
/**
* Adds a value to an existing header, creating a new array if necessary, and canonicalizing the header name.
*
* @param headers - The headers object.
* @param key - The header name to add to.
* @param value - The value to add.
*/
export function addHeader(headers: Headers, key: string, value: string) {
canonicalizeHeaders(headers);
const canonKey = canonicalizeHeaderName(key);
let list = headers[canonKey];
if (!list) {
list = [];
} else if (!Array.isArray(list)) {
list = [list];
}
headers[canonKey] = list;
list.push(value);
}
/**
* Canonicalizes a header value, converting numbers to strings.
*
* @param value - The value to canonicalize.
* @returns The canonicalized value as a string.
*/
function canonicalizeValue(value: any): any {
if (typeof value === 'number') return value.toString();
return value;
}
/**
* Canonicalizes all headers in the headers object by ensuring consistent header names and values.
*
* @param hdr - The headers object to canonicalize.
* @returns The headers object with canonicalized header names and values.
*/
export function canonicalizeHeaders(hdr: Headers): Headers {
for (const [key, values] of Object.entries(hdr)) {
const canonKey = canonicalizeHeaderName(key);
if (!hdr[canonKey]) hdr[canonKey] = [];
if (!Array.isArray(hdr[canonKey]))
hdr[canonKey] = [canonicalizeValue(hdr[canonKey])];
if (key === canonKey) continue;
delete hdr[key];
(hdr[canonKey] as any).push(
...[values].flat().map((value) => canonicalizeValue(value)),
);
}
return hdr;
}
/**
* Removes a header from the headers object.
*
* @param headers - The headers object.
* @param needle - The header name to remove.
*/
export function removeHeader(headers: Headers, needle: string) {
canonicalizeHeaders(headers);
const canonKey = canonicalizeHeaderName(needle);
delete headers[canonKey];
}
/**
* Converts a headers object into an array of tuples, where each tuple represents a header name and value.
*
* @param {Object|string[][]} headers - The headers object or undefined/null.
* @returns {string[][]} An array of tuples where each tuple contains a header name and its corresponding value.
*
* @example
* // Example headers object
* const headers = {
* 'Set-Cookie': 'a=b',
* 'Set-Cookie': 'x=y'
* };
*
* // Converted to an array of tuples
* const result = convertHeadersToTuples(headers);
* console.log(result);
* // Output: [
* // ["Set-Cookie", "a=b"],
* // ["Set-Cookie", "x=y"]
* // ]
*/
export function flatHeaders(
headers: Headers | undefined | null,
): [string, string][] {
if (!headers) return [];
return Object.entries(headers).flatMap(([header, values]) =>
Array.isArray(values)
? values.map((value): [string, string] => [header, value])
: [[header, values]],
);
}