Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ssg): fix path parser bug & refactor code #1976

Merged
merged 5 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 29 additions & 16 deletions deno_dist/helper/ssg/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,40 @@ export const dirname = (path: string) => {
return splitedPath.slice(0, -1).join('/') // Windows supports slash path
}

export const joinPaths = (...paths: string[]) => {
paths = paths.map((path) => {
return path.replace(/(\\)/g, '/').replace(/\/$/g, '')
})
const resultPaths: string[] = []
for (let path of paths.join('/').split('/')) {
const normalizePath = (path: string) => {
return path.replace(/(\\)/g, '/').replace(/\/$/g, '')
}

const handleDotDot = (resultPaths: string[]) => {
if (resultPaths.length === 0) {
resultPaths.push('..')
} else {
resultPaths.pop()
}
}

const handleNonDot = (path: string, resultPaths: string[]) => {
path = path.replace(/^\.(?!.)/, '')
if (path !== '') {
resultPaths.push(path)
}
}

const handleSegments = (paths: string[], resultPaths: string[]) => {
for (const path of paths) {
// Handle `..` or `../`
if (path === '..') {
if (resultPaths.length === 0) {
resultPaths.push('..')
} else {
resultPaths.pop()
}
continue
handleDotDot(resultPaths)
} else {
// Handle `.` or `./`
path = path.replace(/^\./g, '')
}
if (path !== '') {
resultPaths.push(path)
handleNonDot(path, resultPaths)
}
}
}

export const joinPaths = (...paths: string[]) => {
paths = paths.map(normalizePath)
const resultPaths: string[] = []
handleSegments(paths.join('/').split('/'), resultPaths)
return (paths[0][0] === '/' ? '/' : '') + resultPaths.join('/')
}
15 changes: 12 additions & 3 deletions src/helper/ssg/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,23 @@ import { joinPaths, dirname } from './utils'

describe('joinPath', () => {
it('Should joined path is valid.', () => {
expect(joinPaths('test', 'test2')).toBe('test/test2')
expect(joinPaths('test', 'test2', '../test3')).toBe('test/test3')
expect(joinPaths('.', '../')).toBe('..')
expect(joinPaths('test')).toBe('test') //single
expect(joinPaths('.test')).toBe('.test') //single with dot
expect(joinPaths('/.test')).toBe('/.test') //single with dot with root
expect(joinPaths('test', 'test2')).toBe('test/test2') // single and single
expect(joinPaths('test', 'test2', '../test3')).toBe('test/test3') // single and single and single with parent
expect(joinPaths('.', '../')).toBe('..') // dot and parent
expect(joinPaths('test/', 'test2/')).toBe('test/test2') // trailing slashes
expect(joinPaths('./test', './test2')).toBe('test/test2') // dot and slash
expect(joinPaths('', 'test')).toBe('test') // empty path
expect(joinPaths('/test', '/test2')).toBe('/test/test2') // root path
expect(joinPaths('../', 'test')).toBe('../test') // parent and single
expect(joinPaths('test', '..', 'test2')).toBe('test2') // single triple dot and single
expect(joinPaths('test', '...', 'test2')).toBe('test/.../test2') // single triple dot and single
expect(joinPaths('test', './test2', '.test3.')).toBe('test/test2/.test3.') // single and single with slash and single with dot
expect(joinPaths('test', '../', '.test2')).toBe('.test2') // single and parent and single with dot
expect(joinPaths('.test../test2/../')).toBe('.test..') //shuffle
expect(joinPaths('.test./.test2/../')).toBe('.test.') //shuffle2
})
it('Should windows path is valid.', () => {
expect(joinPaths('a\\b\\c', 'd\\e')).toBe('a/b/c/d/e')
Expand Down
45 changes: 29 additions & 16 deletions src/helper/ssg/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,40 @@ export const dirname = (path: string) => {
return splitedPath.slice(0, -1).join('/') // Windows supports slash path
}

export const joinPaths = (...paths: string[]) => {
paths = paths.map((path) => {
return path.replace(/(\\)/g, '/').replace(/\/$/g, '')
})
const resultPaths: string[] = []
for (let path of paths.join('/').split('/')) {
const normalizePath = (path: string) => {
return path.replace(/(\\)/g, '/').replace(/\/$/g, '')
}

const handleDotDot = (resultPaths: string[]) => {
if (resultPaths.length === 0) {
resultPaths.push('..')
} else {
resultPaths.pop()
}
}

const handleNonDot = (path: string, resultPaths: string[]) => {
path = path.replace(/^\.(?!.)/, '')
if (path !== '') {
resultPaths.push(path)
}
}

const handleSegments = (paths: string[], resultPaths: string[]) => {
for (const path of paths) {
// Handle `..` or `../`
if (path === '..') {
if (resultPaths.length === 0) {
resultPaths.push('..')
} else {
resultPaths.pop()
}
continue
handleDotDot(resultPaths)
} else {
// Handle `.` or `./`
path = path.replace(/^\./g, '')
}
if (path !== '') {
resultPaths.push(path)
handleNonDot(path, resultPaths)
}
}
}

export const joinPaths = (...paths: string[]) => {
paths = paths.map(normalizePath)
const resultPaths: string[] = []
handleSegments(paths.join('/').split('/'), resultPaths)
return (paths[0][0] === '/' ? '/' : '') + resultPaths.join('/')
}