Resolve a relative path to the application root (#665)
Summary: This is necessary for #643. If we’re serving `/prototype/index.html`, we need to to use `..` to refer to the root of the site. This patch adds `rootFromPath`, which performs the relevant transformation. (The implementation is trivial, but figuring out exactly what the specification should be was not!) Test Plan: Unit tests added; `yarn test` suffices. wchargin-branch: rootFromPath
This commit is contained in:
parent
c1997d041f
commit
621a93851c
|
@ -40,3 +40,26 @@ export class Assets {
|
|||
return normalize(`${this._getRoot()}/${path}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an absolute path `p`, return a relative path `r` such that a
|
||||
* web page at pathname `p` should use `r` to refer to the root of the
|
||||
* application. The result will only contain components `.` and `..`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - "/foo/" maps to "..";
|
||||
* - "/foo/bar" also maps to "..";
|
||||
* - "/foo/bar/" maps to "../..";
|
||||
* - "/" maps to ".".
|
||||
*
|
||||
* If the argument does not start with "/", an error will be thrown.
|
||||
*/
|
||||
export function rootFromPath(path: string) {
|
||||
const normalized = normalize(path);
|
||||
if (normalized[0] !== "/") {
|
||||
throw new Error("expected absolute path: " + JSON.stringify(path));
|
||||
}
|
||||
const levels = (normalized.match(/\//g) || []).length;
|
||||
return normalize(new Array(levels - 1).fill("..").join("/"));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import {Assets} from "./assets";
|
||||
import {Assets, rootFromPath} from "./assets";
|
||||
|
||||
describe("app/assets", () => {
|
||||
describe("Assets", () => {
|
||||
|
@ -161,4 +161,62 @@ describe("app/assets", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("rootFromPath", () => {
|
||||
it("throws on the empty path", () => {
|
||||
expect(() => rootFromPath("")).toThrow('expected absolute path: ""');
|
||||
});
|
||||
it('throws on an implicitly relative path ("wat")', () => {
|
||||
expect(() => rootFromPath("wat")).toThrow(
|
||||
'expected absolute path: "wat"'
|
||||
);
|
||||
});
|
||||
it('throws on an explicitly relative path ("./wat")', () => {
|
||||
expect(() => rootFromPath("./wat")).toThrow(
|
||||
'expected absolute path: "./wat"'
|
||||
);
|
||||
});
|
||||
describe('returns "." for a path at root', () => {
|
||||
it('with no file component ("/")', () => {
|
||||
expect(rootFromPath("/")).toEqual(".");
|
||||
});
|
||||
it('with a file component ("/index.html")', () => {
|
||||
expect(rootFromPath("/index.html")).toEqual(".");
|
||||
});
|
||||
it('with superfluous slashes ("///")', () => {
|
||||
expect(rootFromPath("///")).toEqual(".");
|
||||
});
|
||||
it('with indirection, like "/foo/../"', () => {
|
||||
expect(rootFromPath("/foo/../")).toEqual(".");
|
||||
});
|
||||
});
|
||||
describe('returns ".." for a path one level deep', () => {
|
||||
it('with no file component ("/foo/")', () => {
|
||||
expect(rootFromPath("/foo/")).toEqual("..");
|
||||
});
|
||||
it('with a file component ("/foo/index.html")', () => {
|
||||
expect(rootFromPath("/foo/index.html")).toEqual("..");
|
||||
});
|
||||
it('with superfluous slashes ("//foo//")', () => {
|
||||
expect(rootFromPath("//foo//")).toEqual("..");
|
||||
});
|
||||
it('with indirection, like "/foo/bar/../"', () => {
|
||||
expect(rootFromPath("/foo/bar/../")).toEqual("..");
|
||||
});
|
||||
});
|
||||
describe('returns "../.." for a path two levels deep', () => {
|
||||
it('with no file component ("/foo/bar/")', () => {
|
||||
expect(rootFromPath("/foo/bar/")).toEqual("../..");
|
||||
});
|
||||
it('with a file component ("/foo/bar/index.html")', () => {
|
||||
expect(rootFromPath("/foo/bar/index.html")).toEqual("../..");
|
||||
});
|
||||
it('with superfluous slashes ("//foo//bar//")', () => {
|
||||
expect(rootFromPath("//foo//bar//")).toEqual("../..");
|
||||
});
|
||||
it('with indirection, like "/foo/bar/baz/../"', () => {
|
||||
expect(rootFromPath("/foo/bar/baz/../")).toEqual("../..");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue