@@ -131,3 +131,36 @@ export function isSamePath(path1: string, path2: string): boolean {
131131
132132 return path1 === path2
133133}
134+
135+ /**
136+ * Normalizes the given path by removing leading, trailing and doubled slashes and also removing the dot sections.
137+ *
138+ * @param path - The path to normalize
139+ */
140+ export function normalize ( path : string ) : string {
141+ const sections = path . split ( '/' )
142+ . filter ( ( p , index , arr ) => p !== '' || index === 0 || index === ( arr . length - 1 ) ) // remove double // but keep leading and trailing slash
143+ . filter ( ( p ) => p !== '.' ) // remove useless /./ sections
144+
145+ const sanitizedSections : string [ ] = [ ]
146+ for ( const section of sections ) {
147+ const lastSection = sanitizedSections . at ( - 1 )
148+ if ( section === '..' && lastSection !== '..' ) {
149+ // if the current section is ".." for the parent, we remove the last section
150+ // But only if the last section is not also ".." which means that we are in a relative path outside of the root
151+ // Note that absolute paths like "/../../foo" are valid as they resolve to "/foo"
152+ if ( lastSection === undefined ) {
153+ // if there is no last section, we are at the root and we can't go up further
154+ // so we keep the ".." section as this is a relative path outside of the root
155+ sanitizedSections . push ( section )
156+ } else if ( lastSection !== '' ) {
157+ // only remove parent if its not the root (leading slash)
158+ sanitizedSections . pop ( )
159+ }
160+ } else {
161+ sanitizedSections . push ( section )
162+ }
163+ }
164+
165+ return sanitizedSections . join ( '/' )
166+ }
0 commit comments