import { Default, Replace } from '@zimic/utils/types'; import { HttpHeadersSchema, HttpHeadersInit, HttpHeadersSchemaName, HttpHeadersSerialized } from './types'; function pickPrimitiveProperties(schema: LooseSchema) { return Object.entries(schema).reduce>((accumulated, [key, value]) => { if (value !== undefined) { accumulated[key] = String(value); } return accumulated; }, {}); } /** @see {@link https://zimic.dev/docs/http/api/http-headers `HttpHeaders` API reference} */ class HttpHeaders extends Headers { readonly _schema!: HttpHeadersSerialized; constructor(init?: HttpHeadersInit) { if (init instanceof Headers || Array.isArray(init) || !init) { super(init); } else { super(pickPrimitiveProperties(init)); } } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersset `headers.set()` API reference} */ set>(name: Name, value: NonNullable): void { super.set(name, value); } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersappend `headers.append()` API reference} */ append>(name: Name, value: NonNullable): void { super.append(name, value); } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersget `headers.get()` API reference} */ get>( name: Name, ): Replace { return super.get(name) as never; } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersgetsetcookie `headers.getSetCookie()` API reference} */ getSetCookie(): NonNullable>[] { return super.getSetCookie() as never; } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headershas `headers.has()` API reference} */ has>(name: Name): boolean { return super.has(name); } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersdelete `headers.delete()` API reference} */ delete>(name: Name): void { super.delete(name); } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersforeach `headers.forEach()` API reference} */ forEach>( callback: >( value: NonNullable & string, key: Key, headers: Headers, ) => void, thisArg?: This, ): void { super.forEach(callback as (value: string, key: string, parent: Headers) => void, thisArg); } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headerskeys `headers.keys()` API reference} */ keys(): HeadersIterator> { return super.keys() as never; } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersvalues `headers.values()` API reference} */ values(): HeadersIterator]> & string> { return super.values() as never; } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersentries `headers.entries()` API reference} */ entries(): HeadersIterator< [ HttpHeadersSchemaName, NonNullable]> & string, ] > { return super.entries() as never; } [Symbol.iterator](): HeadersIterator< [ HttpHeadersSchemaName, NonNullable]> & string, ] > { return super[Symbol.iterator]() as never; } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersequals `headers.equals()` API reference} */ equals(otherHeaders: HttpHeaders): boolean { if (!this.contains(otherHeaders)) { return false; } for (const headerName of this.keys()) { if (!super.has.call(otherHeaders, headerName)) { return false; } } return true; } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headerscontains `headers.contains()` API reference} */ contains(otherHeaders: HttpHeaders): boolean { for (const [headerName, otherHeaderValue] of otherHeaders.entries()) { const headerValue = super.get.call(this, headerName); if (headerValue === null) { return false; } const headerValueItems = this.splitHeaderValues(headerValue); const otherHeaderValueItems = this.splitHeaderValues(otherHeaderValue); const haveSameNumberOfHeaderValues = headerValueItems.length === otherHeaderValueItems.length; if (!haveSameNumberOfHeaderValues) { return false; } for (const otherValueItem of otherHeaderValueItems) { if (!headerValueItems.includes(otherValueItem)) { return false; } } } return true; } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headersassign `headers.assign()` API reference} */ assign(...otherHeadersArray: HttpHeaders[]) { for (const otherHeaders of otherHeadersArray) { if (this === (otherHeaders as unknown)) { continue; } for (const headerName of otherHeaders.keys()) { super.delete(headerName); } for (const [headerName, headerValue] of otherHeaders.entries()) { super.append(headerName, headerValue); } } } /** @see {@link https://zimic.dev/docs/http/api/http-headers#headerstoobject `headers.toObject()` API reference} */ toObject(): this['_schema'] { const object = {} as this['_schema']; for (const [headerName, headerValue] of this.entries()) { object[headerName] = headerValue; } return object; } private splitHeaderValues(value: string) { return value .split(',') .map((item) => item.trim()) .filter((item) => item.length > 0); } } export default HttpHeaders;