Skip to content

Commit

Permalink
refactor impl
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Nov 15, 2023
1 parent f90cfdd commit 8edb24d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 87 deletions.
85 changes: 24 additions & 61 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,91 +50,54 @@ export function isScriptProtocol(protocol?: string) {
}

const TRAILING_SLASH_RE = /\/$|\/\?|\/#/;
const HTTP_PROTOCOL_RE = /^https?:\/\//;

export function hasTrailingSlash(input = "", queryParameters = false): boolean {
if (!queryParameters) {
export function hasTrailingSlash(input = "", respectQueryAndFragment?: boolean): boolean {
if (!respectQueryAndFragment) {
return input.endsWith("/");
}
return TRAILING_SLASH_RE.test(input);
}

export function withoutTrailingSlash(
input = "",
queryParameters = false,
protocol = false
): string {
if (protocol) {
const hasProtocolDifferentThanHttp =
hasProtocol(input) && !HTTP_PROTOCOL_RE.test(input);
if (hasProtocolDifferentThanHttp) {
return input;
}
}
if (!queryParameters) {
export function withoutTrailingSlash(input = "", respectQueryAndFragment?: boolean): string {
if (!respectQueryAndFragment) {
const url = hasTrailingSlash(input) ? input.slice(0, -1) : input;
return url || "/";
}
if (!hasTrailingSlash(input, true)) {
return input || "/";
}

let inputToProcess = input;
let suffix = "";

if (hasFragment(input)) {
const fragmentIndex = input.indexOf("#");
inputToProcess = input.slice(0, fragmentIndex);
suffix = input.slice(fragmentIndex);
let path = input;
let fragment = "";
const fragmentIndex = input.indexOf("#");
if (fragmentIndex>=0) {
path = input.slice(0, fragmentIndex);
fragment = input.slice(fragmentIndex);
}

const [s0, ...s] = inputToProcess.split("?");

const [s0, ...s] = path.split("?");
return (
(s0.slice(0, -1) || "/") + (s.length > 0 ? `?${s.join("?")}` : "") + suffix
(s0.slice(0, -1) || "/") + (s.length > 0 ? `?${s.join("?")}` : "") + fragment
);
}

const FRAGMENT_RE = /#/;

export function hasFragment(input = ""): boolean {
return FRAGMENT_RE.test(input);
}

export function withTrailingSlash(
input = "",
queryParameters = false,
protocol = false
): string {
if (protocol) {
const hasProtocolDifferentThanHttp =
hasProtocol(input) && !HTTP_PROTOCOL_RE.test(input);
if (hasProtocolDifferentThanHttp) {
return input;
}
}
if (!queryParameters) {
export function withTrailingSlash(input = "", respectQueryAndFragment?: boolean): string {
if (!respectQueryAndFragment) {
return input.endsWith("/") ? input : input + "/";
}
if (hasTrailingSlash(input, true)) {
return input || "/";
}

let inputToProcess = input;
let suffix = "";

if (hasFragment(input)) {
const fragmentIndex = input.indexOf("#");
inputToProcess = input.slice(0, fragmentIndex);
suffix = input.slice(fragmentIndex);
if (!inputToProcess) {
return suffix;
let path = input;
let fragment = "";
const fragmentIndex = input.indexOf("#");
if (fragmentIndex >= 0) {
path = input.slice(0, fragmentIndex);
fragment = input.slice(fragmentIndex);
if (!path) {
return fragment;
}
}

const [s0, ...s] = inputToProcess.split("?");

return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : "") + suffix;
const [s0, ...s] = path.split("?");
return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : "") + fragment;
}

export function hasLeadingSlash(input = ""): boolean {
Expand Down
28 changes: 2 additions & 26 deletions test/trailing-slash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,6 @@ describe("withTrailingSlash, queryParams: false", () => {
});
});

describe("withTrailingSlash, protocol: true", () => {
const tests = {
"mailto:example@example.com": "mailto:example@example.com",
};

for (const input in tests) {
test(input, () => {
expect(withTrailingSlash(input, false, true)).toBe(tests[input]);
});
}
});

describe("withTrailingSlash, queryParams: true", () => {
const tests = {
"": "/",
Expand All @@ -43,8 +31,9 @@ describe("withTrailingSlash, queryParams: true", () => {
"foo?123": "foo/?123",
"foo/?123": "foo/?123",
"foo?123#abc": "foo/?123#abc",
// Only fragment should stay as is (without trailing slash)
'/#abc': '/#abc',
"#abc": "#abc",
'#': '#',
};

for (const input in tests) {
Expand Down Expand Up @@ -93,7 +82,6 @@ describe("withoutTrailingSlash, queryParams: true", () => {
"foo/?123": "foo?123",
"foo/?123#abc": "foo?123#abc",
"/a/#abc": "/a#abc",
// Only fragment should stay as is (with trailing slash)
"/#abc": "/#abc",
};

Expand All @@ -107,15 +95,3 @@ describe("withoutTrailingSlash, queryParams: true", () => {
expect(withoutTrailingSlash()).toBe("/");
});
});

describe("withTrailingSlash, protocol: true", () => {
const tests = {
"scheme://host:port/path/": "scheme://host:port/path/",
};

for (const input in tests) {
test(input, () => {
expect(withoutTrailingSlash(input, false, true)).toBe(tests[input]);
});
}
});

0 comments on commit 8edb24d

Please sign in to comment.