diff --git a/examples/.gitkeep b/examples/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/__test__/fetchers/common.test.ts b/src/__test__/fetchers/common.test.ts new file mode 100644 index 0000000..c067491 --- /dev/null +++ b/src/__test__/fetchers/common.test.ts @@ -0,0 +1,48 @@ +import { makeFullUrl } from "@/fetchers/common"; +import { describe, expect, it } from "vitest"; + +describe("makeFullUrl()", () => { + it('should pass normal url if no options', () => { + expect(makeFullUrl('https://example.com/hello/world')).toEqual("https://example.com/hello/world") + expect(makeFullUrl('https://example.com/hello/world?a=b')).toEqual("https://example.com/hello/world?a=b") + expect(makeFullUrl('https://example.com/hello/world?a=b#hello')).toEqual("https://example.com/hello/world?a=b#hello") + expect(makeFullUrl('https://example.com/hello/world#hello')).toEqual("https://example.com/hello/world#hello") + }) + + it('should append baseurl correctly', () => { + const correctResult = "https://example.com/hello/world"; + expect(makeFullUrl(correctResult, { baseUrl: '' })).toEqual(correctResult) + expect(makeFullUrl('/hello/world', { baseUrl: 'https://example.com' })).toEqual(correctResult) + expect(makeFullUrl('/hello/world', { baseUrl: 'https://example.com/' })).toEqual(correctResult) + expect(makeFullUrl('hello/world', { baseUrl: 'https://example.com/' })).toEqual(correctResult) + expect(makeFullUrl('hello/world', { baseUrl: 'https://example.com' })).toEqual(correctResult) + expect(makeFullUrl('/world', { baseUrl: 'https://example.com/hello' })).toEqual(correctResult) + expect(makeFullUrl('/world', { baseUrl: 'https://example.com/hello/' })).toEqual(correctResult) + expect(makeFullUrl('world', { baseUrl: 'https://example.com/hello/' })).toEqual(correctResult) + expect(makeFullUrl('world', { baseUrl: 'https://example.com/hello' })).toEqual(correctResult) + expect(makeFullUrl('world?a=b', { baseUrl: 'https://example.com/hello' })).toEqual("https://example.com/hello/world?a=b") + }) + + it('should throw with invalid baseurl combinations', () => { + expect(() => makeFullUrl('example.com/hello/world', { baseUrl: '' })).toThrowError() + expect(() => makeFullUrl('/hello/world', { baseUrl: 'example.com' })).toThrowError() + expect(() => makeFullUrl('/hello/world', { baseUrl: 'tcp://example.com' })).toThrowError() + expect(() => makeFullUrl('/hello/world', { baseUrl: 'tcp://example.com' })).toThrowError() + }) + + it('should add/merge query parameters', () => { + expect(makeFullUrl('https://example.com/hello/world', { query: { a: 'b' } })).toEqual("https://example.com/hello/world?a=b") + expect(makeFullUrl('https://example.com/hello/world/', { query: { a: 'b' } })).toEqual("https://example.com/hello/world/?a=b") + expect(makeFullUrl('https://example.com', { query: { a: 'b' } })).toEqual("https://example.com/?a=b") + expect(makeFullUrl('https://example.com/', { query: { a: 'b' } })).toEqual("https://example.com/?a=b") + + expect(makeFullUrl('https://example.com/hello/world?c=d', { query: { a: 'b' } })).toEqual("https://example.com/hello/world?c=d&a=b") + expect(makeFullUrl('https://example.com/hello/world?c=d', { query: {} })).toEqual("https://example.com/hello/world?c=d") + expect(makeFullUrl('https://example.com/hello/world?c=d')).toEqual("https://example.com/hello/world?c=d") + expect(makeFullUrl('https://example.com/hello/world?c=d', {})).toEqual("https://example.com/hello/world?c=d") + }) + + it('should work with a mix of multiple options', () => { + expect(makeFullUrl('/hello/world?c=d', { baseUrl: 'https://example.com/', query: { a: 'b' } })).toEqual("https://example.com/hello/world?c=d&a=b") + }) +}) diff --git a/src/fetchers/common.ts b/src/fetchers/common.ts index e0c1780..e31b6d1 100644 --- a/src/fetchers/common.ts +++ b/src/fetchers/common.ts @@ -1,10 +1,22 @@ import { Fetcher, FetcherOptions, UseableFetcher } from '@/fetchers/types'; +export type FullUrlOptions = Pick; + // make url with query params and base url used correctly -export function makeFullUrl(url: string, ops?: FetcherOptions): string { +export function makeFullUrl(url: string, ops?: FullUrlOptions): string { // glue baseUrl and rest of url together - const fullUrl = ops?.baseUrl ?? ''; - // TODO make full url + let leftSide = ops?.baseUrl ?? ''; + let rightSide = url; + + // left side should always end with slash, if its set + if (leftSide.length > 0 && !leftSide.endsWith('/')) leftSide += '/'; + + // right side should never start with slash + if (rightSide.startsWith('/')) rightSide = rightSide.slice(1); + + const fullUrl = leftSide + rightSide; + if (!fullUrl.startsWith('http://') && !fullUrl.startsWith('https://')) + throw new Error(`Invald URL -- URL doesn't start with a http scheme: '${fullUrl}'`); const parsedUrl = new URL(fullUrl); Object.entries(ops?.query ?? {}).forEach(([k, v]) => {