mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-31 18:07:00 +02:00
95 lines
3 KiB
TypeScript
95 lines
3 KiB
TypeScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
export function normalizeUrl(rawUrls: string[]): string {
|
|
const urls = [...rawUrls];
|
|
const resultArray = [];
|
|
|
|
let hasStartingSlash = false;
|
|
let hasEndingSlash = false;
|
|
|
|
// If the first part is a plain protocol, we combine it with the next part.
|
|
if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
|
|
const first = urls.shift();
|
|
if (first!.startsWith('file:') && urls[0].startsWith('/')) {
|
|
// Force a double slash here, else we lose the information that the next segment is an absolute path
|
|
urls[0] = `${first}//${urls[0]}`;
|
|
} else {
|
|
urls[0] = first + urls[0];
|
|
}
|
|
}
|
|
|
|
// There must be two or three slashes in the file protocol,
|
|
// two slashes in anything else.
|
|
const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
|
|
urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement);
|
|
|
|
// eslint-disable-next-line
|
|
for (let i = 0; i < urls.length; i++) {
|
|
let component = urls[i];
|
|
|
|
if (typeof component !== 'string') {
|
|
throw new TypeError(`Url must be a string. Received ${typeof component}`);
|
|
}
|
|
|
|
if (component === '') {
|
|
if (i === urls.length - 1 && hasEndingSlash) {
|
|
resultArray.push('/');
|
|
}
|
|
// eslint-disable-next-line
|
|
continue;
|
|
}
|
|
|
|
if (component !== '/') {
|
|
if (i > 0) {
|
|
// Removing the starting slashes for each component but the first.
|
|
component = component.replace(
|
|
/^[/]+/,
|
|
// Special case where the first element of rawUrls is empty ["", "/hello"] => /hello
|
|
component[0] === '/' && !hasStartingSlash ? '/' : '',
|
|
);
|
|
}
|
|
|
|
hasEndingSlash = component[component.length - 1] === '/';
|
|
// Removing the ending slashes for each component but the last.
|
|
// For the last component we will combine multiple slashes to a single one.
|
|
component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/');
|
|
}
|
|
|
|
hasStartingSlash = true;
|
|
resultArray.push(component);
|
|
}
|
|
|
|
let str = resultArray.join('/');
|
|
// Each input component is now separated by a single slash
|
|
// except the possible first plain protocol part.
|
|
|
|
// Remove trailing slash before parameters or hash.
|
|
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
|
|
|
|
// Replace ? in parameters with &.
|
|
const parts = str.split('?');
|
|
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
|
|
|
|
// Dedupe forward slashes in the entire path, avoiding protocol slashes.
|
|
str = str.replace(/([^:/]\/)\/+/g, '$1');
|
|
|
|
// Dedupe forward slashes at the beginning of the path.
|
|
str = str.replace(/^\/+/g, '/');
|
|
|
|
return str;
|
|
}
|
|
|
|
export function getEditUrl(
|
|
fileRelativePath: string,
|
|
editUrl?: string,
|
|
): string | undefined {
|
|
return editUrl
|
|
? // Don't use posixPath for this: we need to force a forward slash path
|
|
normalizeUrl([editUrl, fileRelativePath.replace(/\\/g, '/')])
|
|
: undefined;
|
|
}
|