From 89d5a358a79db003f7ed419798100f4b17d7dff4 Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Thu, 26 Apr 2018 23:17:15 +0200 Subject: [PATCH] fix(router): root prop --- core/package-lock.json | 8 +- core/src/components/router/test/path.spec.tsx | 95 ++++++++++++++++++- core/src/components/router/utils/path.ts | 37 ++++++-- 3 files changed, 127 insertions(+), 13 deletions(-) diff --git a/core/package-lock.json b/core/package-lock.json index 5257876cec..996f258d3a 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -34,9 +34,9 @@ } }, "@stencil/core": { - "version": "0.7.27-0", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.7.27-0.tgz", - "integrity": "sha512-Lh2826KcXW7O1K8rr4Ga4OCcZiwS0BTQCCIboZVTTAhMjgHJ4Ocv2/AIxMKhQea4O46Y93UA+7GopFGF0AMQZw==", + "version": "0.7.27-3", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.7.27-3.tgz", + "integrity": "sha512-WGrT8o29wBu+4lFwOWgQEMKr9LCBlSiGuvWoIf/nyM3bIZ5ywtGI6/QrTy1fXsXeMC7yGlB+YTCqaSCC+eHdfw==", "dev": true, "requires": { "chokidar": "2.0.3", @@ -47,7 +47,7 @@ "rollup-plugin-node-globals": "1.2.0", "rollup-plugin-node-resolve": "3.3.0", "rollup-pluginutils": "2.0.1", - "typescript": "^2.8.1", + "typescript": "^2.8.3", "uglify-es": "3.3.9", "workbox-build": "^3.1.0" } diff --git a/core/src/components/router/test/path.spec.tsx b/core/src/components/router/test/path.spec.tsx index 0ef9ea6cb6..fcadc04509 100644 --- a/core/src/components/router/test/path.spec.tsx +++ b/core/src/components/router/test/path.spec.tsx @@ -1,11 +1,16 @@ import { RouteChain } from '../utils/interface'; -import { chainToPath, generatePath, parsePath } from '../utils/path'; +import { chainToPath, generatePath, parsePath, readPath } from '../utils/path'; describe('parseURL', () => { it('should parse empty path', () => { expect(parsePath('')).toEqual(['']); }); + it('should parse slash path', () => { + expect(parsePath('/')).toEqual(['']); + expect(parsePath(' / ')).toEqual(['']); + }); + it('should parse empty path (2)', () => { expect(parsePath(' ')).toEqual(['']); }); @@ -18,6 +23,13 @@ describe('parseURL', () => { expect(parsePath(undefined)).toEqual(['']); }); + it('should parse single segment', () => { + expect(parsePath('path')).toEqual(['path']); + expect(parsePath('path/')).toEqual(['path']); + expect(parsePath('/path/')).toEqual(['path']); + expect(parsePath('/path')).toEqual(['path']); + }); + it('should parse relative path', () => { expect(parsePath('path/to/file.js')).toEqual(['path', 'to', 'file.js']); }); @@ -90,3 +102,84 @@ describe('chainToPath', () => { }); }); +describe('readPath', () => { + it('should read the URL from root (no hash)', () => { + const loc = mockLocation('/', ''); + expect(readPath(loc, '', false)).toEqual(['']); + expect(readPath(loc, '/', false)).toEqual(['']); + expect(readPath(loc, ' / ', false)).toEqual(['']); + + expect(readPath(loc, '', true)).toEqual(['']); + expect(readPath(loc, '/', true)).toEqual(['']); + expect(readPath(loc, ' / ', true)).toEqual(['']); + }); + + it('should read the URL from root (hash)', () => { + const loc = mockLocation('/', '#'); + expect(readPath(loc, '', true)).toEqual(['']); + expect(readPath(loc, '/', true)).toEqual(['']); + expect(readPath(loc, ' / ', true)).toEqual(['']); + + const loc2 = mockLocation('/', '#/'); + expect(readPath(loc2, '', true)).toEqual(['']); + expect(readPath(loc2, '/', true)).toEqual(['']); + expect(readPath(loc2, ' / ', true)).toEqual(['']); + }); + + it('should not read the URL from root', () => { + const loc = mockLocation('/', ''); + expect(readPath(loc, '/hola', false)).toBeNull(); + expect(readPath(loc, 'hola', false)).toBeNull(); + + expect(readPath(loc, '/hola', true)).toBeNull(); + expect(readPath(loc, 'hola', true)).toBeNull(); + }); + + it('should read the URL from non root (no hash)', () => { + const loc = mockLocation('/path/to/component', '#hello'); + expect(readPath(loc, '', false)).toEqual(['path', 'to', 'component']); + expect(readPath(loc, '/', false)).toEqual(['path', 'to', 'component']); + expect(readPath(loc, 'path', false)).toEqual(['to', 'component']); + expect(readPath(loc, '/path', false)).toEqual(['to', 'component']); + expect(readPath(loc, '/path/', false)).toEqual(['to', 'component']); + expect(readPath(loc, '/path/to', false)).toEqual(['component']); + expect(readPath(loc, '/path/to/component', false)).toEqual(['']); + expect(readPath(loc, '/path/to/component/', false)).toEqual(['']); + expect(readPath(loc, '/path/to/component/path', false)).toBeNull(); + }); + + it('should read the URL from non root (hash)', () => { + const loc = mockLocation('/index.html', '#path/to/component'); + expect(readPath(loc, '', true)).toEqual(['path', 'to', 'component']); + expect(readPath(loc, '/', true)).toEqual(['path', 'to', 'component']); + expect(readPath(loc, 'path', true)).toEqual(['to', 'component']); + expect(readPath(loc, '/path', true)).toEqual(['to', 'component']); + expect(readPath(loc, '/path/', true)).toEqual(['to', 'component']); + expect(readPath(loc, '/path/to', true)).toEqual(['component']); + expect(readPath(loc, '/path/to/component', true)).toEqual(['']); + expect(readPath(loc, '/path/to/component/', true)).toEqual(['']); + expect(readPath(loc, '/path/to/component/path', true)).toBeNull(); + expect(readPath(loc, '/path/to/component2', true)).toBeNull(); + }); + + it('should read the URL from non root (hash) 2', () => { + const loc = mockLocation('/index.html', '#/path/to/component'); + expect(readPath(loc, '', true)).toEqual(['path', 'to', 'component']); + expect(readPath(loc, '/', true)).toEqual(['path', 'to', 'component']); + expect(readPath(loc, 'path', true)).toEqual(['to', 'component']); + expect(readPath(loc, '/path', true)).toEqual(['to', 'component']); + expect(readPath(loc, '/path/', true)).toEqual(['to', 'component']); + expect(readPath(loc, '/path/to', true)).toEqual(['component']); + expect(readPath(loc, '/path/to/component', true)).toEqual(['']); + expect(readPath(loc, '/path/to/component/', true)).toEqual(['']); + expect(readPath(loc, '/path/to/component/path', true)).toBeNull(); + }); +}); + +function mockLocation(pathname: string, hash: string): Location { + return { + pathname, + hash + } as Location; +} + diff --git a/core/src/components/router/utils/path.ts b/core/src/components/router/utils/path.ts index 6684045166..eacebeb0b2 100644 --- a/core/src/components/router/utils/path.ts +++ b/core/src/components/router/utils/path.ts @@ -39,15 +39,36 @@ export function writePath(history: History, base: string, usePath: boolean, path } } -export function readPath(loc: Location, base: string, useHash: boolean): string[] | null { - const path = useHash - ? loc.hash.substr(1) - : loc.pathname; - - if (path.startsWith(base)) { - return parsePath(path.slice(base.length)); +export function removePrefix(prefix: string[], path: string[]): string[] | null { + if (prefix.length > path.length) { + return null; } - return null; + if (prefix.length <= 1 && prefix[0] === '') { + return path; + } + for (let i = 0; i < prefix.length; i++) { + if (prefix[i].length > 0 && prefix[i] !== path[i]) { + return null; + } + } + if (path.length === prefix.length) { + return ['']; + } + return path.slice(prefix.length); +} + +export function readPath(loc: Location, root: string, useHash: boolean): string[] | null { + let pathname = loc.pathname; + if (useHash) { + const hash = loc.hash; + pathname = (hash[0] === '#') + ? hash.slice(1) + : ''; + } + + const prefix = parsePath(root); + const path = parsePath(pathname); + return removePrefix(prefix, path); } export function parsePath(path: string|undefined|null): string[] {