Skip to content

Commit

Permalink
Merge cddd691 into 34e240c
Browse files Browse the repository at this point in the history
  • Loading branch information
Mister-Hope committed Apr 17, 2024
2 parents 34e240c + cddd691 commit c002052
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 109 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 @@ -2,6 +2,7 @@ export * from './dedupeHead.js'
export * from './ensureLeadingSlash.js'
export * from './ensureEndingSlash.js'
export * from './formatDateString.js'
export * from './inferRoutePath.js'
export * from './isLinkExternal.js'
export * from './isLinkHttp.js'
export * from './isLinkWithProtocol.js'
Expand Down
26 changes: 26 additions & 0 deletions packages/shared/src/utils/inferRoutePath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Infer route path according to the given (markdown file) path
*/
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
}
33 changes: 12 additions & 21 deletions packages/shared/src/utils/normalizeRoutePath.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
import { inferRoutePath } from './inferRoutePath.js'

const FAKE_HOST = 'http://.'

/**
* Normalize the given path to the final route path
*/
export const normalizeRoutePath = (path: string): string => {
// split pathname and query/hash
const [pathname, ...queryAndHash] = path.split(/(\?|#)/)

// if the pathname is empty or ends with `/`, return as is
if (!pathname || pathname.endsWith('/')) return path
export const normalizeRoutePath = (path: string, current?: string): string => {
if (!path.startsWith('/') && current) {
// the relative path should be resolved against the current path
const loc = current.slice(0, current.lastIndexOf('/'))

// convert README.md to index.html
let routePath = pathname.replace(/(^|\/)README.md$/i, '$1index.html')
const { pathname, search, hash } = new URL(`${loc}/${path}`, FAKE_HOST)

// 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'
return inferRoutePath(pathname) + search + hash
}

// convert /foo/index.html to /foo/
if (routePath.endsWith('/index.html')) {
routePath = routePath.substring(0, routePath.length - 10)
}
const [pathname, ...queryAndHash] = path.split(/(\?|#)/)

// add query and hash back
return routePath + queryAndHash.join('')
return inferRoutePath(pathname) + queryAndHash.join('')
}
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)
}),
)
})
Loading

0 comments on commit c002052

Please sign in to comment.