Rewrite urlParser to urlFormater

This commit is contained in:
Sebastian Qvarfordt
2020-06-30 15:39:35 +02:00
parent 6f9270e765
commit 45a981ca04
7 changed files with 130 additions and 90 deletions
@@ -30,7 +30,7 @@ import transformer, {
modifyCss,
} from '../transformers';
import { docStorageURL } from '../../config';
import URLParser from '../urlParser';
import URLFormatter from '../urlFormatter';
const useFetch = (url: string) => {
const state = useAsync(async () => {
@@ -45,7 +45,7 @@ const useFetch = (url: string) => {
const useEnforcedTrailingSlash = (): void => {
React.useEffect(() => {
const actualUrl = window.location.href;
const expectedUrl = new URLParser(window.location.href, '.').parse();
const expectedUrl = new URLFormatter(window.location.href).formatBaseURL();
if (actualUrl !== expectedUrl) {
window.history.replaceState({}, document.title, expectedUrl);
@@ -58,10 +58,9 @@ export const Reader = () => {
const { componentId, '*': path } = useParams();
const shadowDomRef = useShadowDom();
const navigate = useNavigate();
const normalizedUrl = new URLParser(
const normalizedUrl = new URLFormatter(
`${docStorageURL}${location.pathname.replace('/docs', '')}`,
'.',
).parse();
).formatBaseURL();
const state = useFetch(`${normalizedUrl}index.html`);
useEnforcedTrailingSlash();
@@ -89,13 +88,23 @@ export const Reader = () => {
]);
divElement.shadowRoot.innerHTML = '';
if (transformedElement) {
divElement.shadowRoot.appendChild(transformedElement);
transformer(divElement.shadowRoot.children[0], [
dom => {
setTimeout(() => {
if (window.location.hash) {
const hash = window.location.hash.slice(1);
divElement.shadowRoot?.getElementById(hash)?.scrollIntoView();
}
}, 200);
return dom;
},
addLinkClickListener({
onClick: url => {
onClick: (_: MouseEvent, url: string) => {
const parsedUrl = new URL(url);
navigate(parsedUrl.pathname);
navigate(`${parsedUrl.pathname}${parsedUrl.hash}`);
divElement.shadowRoot
?.querySelector(parsedUrl.hash)
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import URLParser from '../urlParser';
import URLFormatter from '../urlFormatter';
import type { Transformer } from './index';
type AddBaseUrlOptions = {
@@ -36,11 +36,13 @@ export const addBaseUrl = ({
Array.from(list)
.filter(elem => !!elem.getAttribute(attributeName))
.forEach((elem: T) => {
const newUrl = new URLParser(
const urlFormatter = new URLFormatter(
`${docStorageURL}/${componentId}/${path}`,
elem.getAttribute(attributeName)!,
).parse();
elem.setAttribute(attributeName, newUrl);
);
elem.setAttribute(
attributeName,
urlFormatter.formatURL(elem.getAttribute(attributeName)!),
);
});
};
@@ -17,7 +17,7 @@
import type { Transformer } from './index';
type AddLinkClickListenerOptions = {
onClick: (newUrl: string) => void;
onClick: (e: MouseEvent, newUrl: string) => void;
};
export const addLinkClickListener = ({
@@ -29,7 +29,7 @@ export const addLinkClickListener = ({
e.preventDefault();
const target = e.target as HTMLAnchorElement;
if (target?.getAttribute('href')) {
onClick(target.getAttribute('href')!);
onClick(e, target.getAttribute('href')!);
}
});
});
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import URLParser from '../urlParser';
import URLFormatter from '../urlFormatter';
import type { Transformer } from './index';
export const rewriteDocLinks = (): Transformer => {
@@ -26,12 +26,10 @@ export const rewriteDocLinks = (): Transformer => {
Array.from(list)
.filter(elem => elem.hasAttribute(attributeName))
.forEach((elem: T) => {
const urlFormatter = new URLFormatter(window.location.href);
elem.setAttribute(
attributeName,
new URLParser(
window.location.href,
elem.getAttribute(attributeName)!,
).parse(),
urlFormatter.formatURL(elem.getAttribute(attributeName)!),
);
});
};
@@ -0,0 +1,84 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import URLFormatter from './urlFormatter';
describe('URLFormatter', () => {
describe('formatURL', () => {
it('should not change an absolute url', () => {
const formatter = new URLFormatter('https://www.google.com/');
expect(formatter.formatURL('https://www.mkdocs.org/')).toEqual(
'https://www.mkdocs.org/',
);
});
it('should convert a relative url to an absolute url', () => {
const formatter = new URLFormatter(
'https://www.mkdocs.org/user-guide/getting-started/',
);
expect(formatter.formatURL('../../support/installing/')).toEqual(
'https://www.mkdocs.org/support/installing/',
);
});
it('should add a trailing slash', () => {
const formatter = new URLFormatter(
'https://www.mkdocs.org/user-guide/getting-started',
);
expect(formatter.formatURL('./getting-started')).toEqual(
'https://www.mkdocs.org/user-guide/getting-started/',
);
});
it('should not add a trailing slash', () => {
const formatter = new URLFormatter(
'https://www.mkdocs.org/user-guide/getting-started/',
);
expect(formatter.formatURL('.')).toEqual(
'https://www.mkdocs.org/user-guide/getting-started/',
);
});
it('should not add multiple hashes', () => {
const formatter = new URLFormatter(
'https://www.mkdocs.org/user-guide/getting-started/#hash1',
);
expect(formatter.formatURL('./#hash2')).toEqual(
'https://www.mkdocs.org/user-guide/getting-started/#hash2',
);
});
});
describe('formatBaseURL', () => {
it('should keep query params in URL', () => {
const formatter = new URLFormatter(
'https://www.mkdocs.org/user-guide/getting-started/?query=hello+world',
);
expect(formatter.formatBaseURL()).toEqual(
'https://www.mkdocs.org/user-guide/getting-started/?query=hello+world',
);
});
it('should keep hash in URL', () => {
const formatter = new URLFormatter(
'https://www.mkdocs.org/user-guide/getting-started/#hash',
);
expect(formatter.formatBaseURL()).toEqual(
'https://www.mkdocs.org/user-guide/getting-started/#hash',
);
});
});
});
@@ -14,18 +14,26 @@
* limitations under the License.
*/
const normalizeBaseURL = (baseURL: string): string => {
const url = new URL(baseURL);
url.pathname = url.pathname.replace(/([^/])$/, '$1/');
return url.toString();
};
export default class URLFormatter {
constructor(public baseURL: string) {}
export default class URLParser {
constructor(public baseURL: string, public pathname: string) {
this.baseURL = normalizeBaseURL(baseURL);
formatBaseURL(): string {
return this.normalizeURL(this.baseURL);
}
parse(): string {
return new URL(this.pathname, this.baseURL).toString();
formatURL(pathname: string): string {
return this.normalizeURL(new URL(pathname, this.baseURL).toString());
}
private normalizeURL(urlString: string): string {
const url = new URL(urlString);
const filename: string = url.pathname.split('/').pop() ?? url.pathname;
const isDir: boolean = filename.includes('.') === false;
if (isDir) {
url.pathname = url.pathname.replace(/([^/])$/, '$1/');
}
return url.toString();
}
}
@@ -1,61 +0,0 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import URLParser from './urlParser';
describe('URLParser', () => {
it('should not change an absolute url', () => {
const urlParser = new URLParser(
'https://www.google.com/',
'https://www.mkdocs.org/',
);
expect(urlParser.parse()).toEqual('https://www.mkdocs.org/');
});
it('should convert a relative url to an absolute url', () => {
const urlParser = new URLParser(
'https://www.mkdocs.org/user-guide/getting-started/',
'../../support/installing/',
);
expect(urlParser.parse()).toEqual(
'https://www.mkdocs.org/support/installing/',
);
});
it('should add a trailing slash', () => {
const urlParser = new URLParser(
'https://www.mkdocs.org/user-guide/getting-started',
'.',
);
expect(urlParser.parse()).toEqual(
'https://www.mkdocs.org/user-guide/getting-started/',
);
});
it('should not add a trailing slash', () => {
const urlParser = new URLParser(
'https://www.mkdocs.org/user-guide/getting-started/',
'.',
);
expect(urlParser.parse()).toEqual(
'https://www.mkdocs.org/user-guide/getting-started/',
);
});
});