Skip to content

Commit

Permalink
Merge branch 'normalizeRoutePath' into route-link
Browse files Browse the repository at this point in the history
  • Loading branch information
Mister-Hope committed Apr 17, 2024
2 parents c12435a + b69d3b3 commit ab3d6e6
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 26 deletions.
1 change: 1 addition & 0 deletions packages/shared/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './isLinkExternal.js'
export * from './isLinkHttp.js'
export * from './isLinkWithProtocol.js'
export * from './isPlainObject.js'
export * from './inferRoutePath.js'
export * from './normalizeRoutePath.js'
export * from './omit.js'
export * from './removeEndingSlash.js'
Expand Down
23 changes: 23 additions & 0 deletions packages/shared/src/utils/inferRoutePath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const inferRoutePath = (path: string): string => {
// if the pathname is empty or ends with `/`, return as is
if (!path || path.endsWith('/')) return path

// convert README.md to index.html
let routePath = path.replace(/(^|\/)README.md$/i, '$1index.html')

// convert /foo/bar.md to /foo/bar.html
if (routePath.endsWith('.md')) {
routePath = routePath.substring(0, routePath.length - 3) + '.html'
}
// convert /foo/bar to /foo/bar.html
else if (!routePath.endsWith('.html')) {
routePath = routePath + '.html'
}

// convert /foo/index.html to /foo/
if (routePath.endsWith('/index.html')) {
routePath = routePath.substring(0, routePath.length - 10)
}

return routePath
}
2 changes: 1 addition & 1 deletion packages/shared/src/utils/isLinkWithProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
* Determine a link has protocol or not
*/
export const isLinkWithProtocol = (link: string): boolean =>
/^[a-z][a-z0-9+.-]*:/.test(link)
/^[a-z][a-z0-9+.-]*:/.test(link) || link.startsWith('//')
26 changes: 2 additions & 24 deletions packages/shared/src/utils/normalizeRoutePath.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,6 @@
const FAKE_HOST = 'http://.'

export const inferRoutePath = (path: string): string => {
// if the pathname is empty or ends with `/`, return as is
if (!path || path.endsWith('/')) return path

// convert README.md to index.html
let routePath = path.replace(/(^|\/)README.md$/i, '$1index.html')

// convert /foo/bar.md to /foo/bar.html
if (routePath.endsWith('.md')) {
routePath = routePath.substring(0, routePath.length - 3) + '.html'
}
// convert /foo/bar to /foo/bar.html
else if (!routePath.endsWith('.html')) {
routePath = routePath + '.html'
}

// convert /foo/index.html to /foo/
if (routePath.endsWith('/index.html')) {
routePath = routePath.substring(0, routePath.length - 10)
}
import { inferRoutePath } from './inferRoutePath.js'

return routePath
}
const FAKE_HOST = 'http://.'

/**
* Normalize the given path to the final route path
Expand Down
62 changes: 62 additions & 0 deletions packages/shared/tests/inferRoutePath.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { describe, expect, it } from 'vitest'
import { inferRoutePath } from '../src/index.js'

const testCases = [
// absolute index
['/', '/'],
['/README.md', '/'],
['/readme.md', '/'],
['/index.md', '/'],
['/index.html', '/'],
['/index', '/'],
['/foo/', '/foo/'],
['/foo/README.md', '/foo/'],
['/foo/readme.md', '/foo/'],
['/foo/index.md', '/foo/'],
['/foo/index.html', '/foo/'],
['/foo/index', '/foo/'],
['README.md', 'index.html'],
['readme.md', 'index.html'],
['index.md', 'index.html'],
['index.html', 'index.html'],
['index', 'index.html'],

// absolute non-index
['/foo', '/foo.html'],
['/foo.md', '/foo.html'],
['/foo.html', '/foo.html'],
['/foo/bar', '/foo/bar.html'],
['/foo/bar.md', '/foo/bar.html'],
['/foo/bar.html', '/foo/bar.html'],

// relative index without current
['foo/', 'foo/'],
['foo/README.md', 'foo/'],
['foo/readme.md', 'foo/'],
['foo/index.md', 'foo/'],
['foo/index.html', 'foo/'],
['foo/index', 'foo/'],

// relative non index without current
['foo', 'foo.html'],
['foo.md', 'foo.html'],
['foo.html', 'foo.html'],
['foo/bar', 'foo/bar.html'],
['foo/bar.md', 'foo/bar.html'],
['foo/bar.html', 'foo/bar.html'],

// unexpected corner cases
['', ''],
['.md', '.html'],
['foo/.md', 'foo/.html'],
['/.md', '/.html'],
['/foo/.md', '/foo/.html'],
]

describe('should normalize clean paths correctly', () => {
testCases.forEach(([path, expected]) =>
it(`"${path}" -> "${expected}"`, () => {
expect(inferRoutePath(path)).toBe(expected)
}),
)
})
11 changes: 10 additions & 1 deletion packages/shared/tests/isLinkWithProtocol.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ import { expect, it } from 'vitest'
import { isLinkWithProtocol } from '../src/index.js'

const testCases: [string, ReturnType<typeof isLinkWithProtocol>][] = [
// with protocol
['ftp://foobar.com', true],
['ms-windows-store://home', true],
['mailto:foobar', true],
['tel:foobar', true],
['https://foobar.com', true],
['http://foobar.com', true],
['//foobar.com', true],

// hostname
['foobar.com', false],

// pathname
['/foo/bar', false],

// relative path
['../foo/bar', false],
['//foobar.com', false],
['./foo/bar', false],
['foo/bar', false],
]

testCases.forEach(([source, expected]) => {
Expand Down

0 comments on commit ab3d6e6

Please sign in to comment.