Răsfoiți Sursa

Merge pull request #2678 from kasoki/enhance_path

Add ability to normalize and join paths to haxe.io.Path
Simon Krajewski 11 ani în urmă
părinte
comite
54ebe3c7e3
2 a modificat fișierele cu 87 adăugiri și 29 ștergeri
  1. 78 29
      std/haxe/io/Path.hx
  2. 9 0
      tests/unit/unitstd/haxe/io/Path.unit.hx

+ 78 - 29
std/haxe/io/Path.hx

@@ -24,7 +24,7 @@ package haxe.io;
 /**
 /**
 	This class provides a convenient way of working with paths. It supports the
 	This class provides a convenient way of working with paths. It supports the
 	common path formats:
 	common path formats:
-		
+
 	- directory1/directory2/filename.extension
 	- directory1/directory2/filename.extension
 	- directory1\directory2\filename.excention
 	- directory1\directory2\filename.excention
 **/
 **/
@@ -32,36 +32,36 @@ class Path {
 
 
 	/**
 	/**
 		The directory.
 		The directory.
-		
+
 		This is the leading part of the path that is not part of the file name
 		This is the leading part of the path that is not part of the file name
 		and the extension.
 		and the extension.
-		
+
 		Does not end with a `/` or `\` separator.
 		Does not end with a `/` or `\` separator.
-		
+
 		If the path has no directory, the value is null.
 		If the path has no directory, the value is null.
 	**/
 	**/
 	public var dir : String;
 	public var dir : String;
-	
+
 	/**
 	/**
 		The file name.
 		The file name.
-		
+
 		This is the part of the part between the directory and the extension.
 		This is the part of the part between the directory and the extension.
-		
+
 		If there is no file name, e.g. for ".htaccess" or "/dir/", the value
 		If there is no file name, e.g. for ".htaccess" or "/dir/", the value
 		is the empty String "".
 		is the empty String "".
 	**/
 	**/
 	public var file : String;
 	public var file : String;
-	
+
 	/**
 	/**
 		The file extension.
 		The file extension.
-		
+
 		It is separated from the file name by a dot. This dot is not part of
 		It is separated from the file name by a dot. This dot is not part of
 		the extension.
 		the extension.
-		
+
 		If the path has no extension, the value is null.
 		If the path has no extension, the value is null.
 	**/
 	**/
 	public var ext : String;
 	public var ext : String;
-		
+
 	/**
 	/**
 		True if the last directory separator is a backslash, false otherwise.
 		True if the last directory separator is a backslash, false otherwise.
 	**/
 	**/
@@ -69,7 +69,7 @@ class Path {
 
 
 	/**
 	/**
 		Creates a new Path instance by parsing `path`.
 		Creates a new Path instance by parsing `path`.
-		
+
 		Path information can be retrieved by accessing the dir, file and ext
 		Path information can be retrieved by accessing the dir, file and ext
 		properties.
 		properties.
 	**/
 	**/
@@ -97,11 +97,11 @@ class Path {
 
 
 	/**
 	/**
 		Returns a String representation of `this` path.
 		Returns a String representation of `this` path.
-		
+
 		If `this.backslash` is true, backslash is used as directory separator,
 		If `this.backslash` is true, backslash is used as directory separator,
 		otherwise slash is used. This only affects the separator between
 		otherwise slash is used. This only affects the separator between
 		`this.dir` and `this.file`.
 		`this.dir` and `this.file`.
-		
+
 		If `this.directory` or `this.extension` is null, their representation
 		If `this.directory` or `this.extension` is null, their representation
 		is the empty String "".
 		is the empty String "".
 	**/
 	**/
@@ -111,7 +111,7 @@ class Path {
 
 
 	/**
 	/**
 		Returns the String representation of `path` without the file extension.
 		Returns the String representation of `path` without the file extension.
-		
+
 		If `path` is null, the result is unspecified.
 		If `path` is null, the result is unspecified.
 	**/
 	**/
 	public static function withoutExtension( path : String ) {
 	public static function withoutExtension( path : String ) {
@@ -122,7 +122,7 @@ class Path {
 
 
 	/**
 	/**
 		Returns the String representation of `path` without the directory.
 		Returns the String representation of `path` without the directory.
-		
+
 		If `path` is null, the result is unspecified.
 		If `path` is null, the result is unspecified.
 	**/
 	**/
 	public static function withoutDirectory( path ) {
 	public static function withoutDirectory( path ) {
@@ -133,9 +133,9 @@ class Path {
 
 
 	/**
 	/**
 		Returns the directory of `path`.
 		Returns the directory of `path`.
-		
+
 		If the directory is null, the empty String "" is returned.
 		If the directory is null, the empty String "" is returned.
-		
+
 		If `path` is null, the result is unspecified.
 		If `path` is null, the result is unspecified.
 	**/
 	**/
 	public static function directory( path ) {
 	public static function directory( path ) {
@@ -147,9 +147,9 @@ class Path {
 
 
 	/**
 	/**
 		Returns the extension of `path`.
 		Returns the extension of `path`.
-		
+
 		If the extension is null, the empty String "" is returned.
 		If the extension is null, the empty String "" is returned.
-		
+
 		If `path` is null, the result is unspecified.
 		If `path` is null, the result is unspecified.
 	**/
 	**/
 	public static function extension( path ) {
 	public static function extension( path ) {
@@ -161,9 +161,9 @@ class Path {
 
 
 	/**
 	/**
 		Returns a String representation of `path` where the extension is `ext`.
 		Returns a String representation of `path` where the extension is `ext`.
-		
+
 		If `path` has no extension, `ext` is added as extension.
 		If `path` has no extension, `ext` is added as extension.
-		
+
 		If `path` or `ext` are null, the result is unspecified.
 		If `path` or `ext` are null, the result is unspecified.
 	**/
 	**/
 	public static function withExtension( path, ext ) {
 	public static function withExtension( path, ext ) {
@@ -172,16 +172,65 @@ class Path {
 		return s.toString();
 		return s.toString();
 	}
 	}
 
 
+	/**
+		Join two paths together and normalize them
+
+		e.g. 'assets/maps' and '../textures/img.png' = 'assets/textures/img.png'
+	**/
+	public static function join( path1 : String, path2 : String ) : String {
+		path1 = Path.addTrailingSlash(path1);
+
+		return Path.normalize(path1 + path2);
+	}
+
+	/**
+		Normalize a given `path` (e.g. make '/usr/local/../lib' to '/usr/lib')
+	**/
+	public static function normalize( path : String) : String {
+		var slash = '/';
+
+		if( path == null || path == slash ) {
+			return slash;
+		}
+
+		var prependSlash = (path.charAt(0) == slash ||
+			path.charAt(0) == '.');
+		var target = [];
+		var src;
+		var parts;
+		var token;
+
+		src = path.split(slash);
+
+		for( i in 0...src.length ) {
+			token = src[i];
+
+			if(token == '..') {
+				target.pop();
+			} else if(token != '' && token != '.') {
+				target.push(token);
+			}
+		}
+
+		var regex = ~/[\/]{2,}/g;
+
+		var tmp = target.join(slash);
+
+		var result = regex.replace(tmp, slash);
+
+		return (prependSlash ? slash : '') + result;
+	}
+
 	/**
 	/**
 		Adds a trailing slash to `path`, if it does not have one already.
 		Adds a trailing slash to `path`, if it does not have one already.
-		
+
 		If the last slash in `path` is a backslash, a backslash is appended to
 		If the last slash in `path` is a backslash, a backslash is appended to
 		`path`.
 		`path`.
-		
+
 		If the last slash in `path` is a slash, or if no slash is found, a slash
 		If the last slash in `path` is a slash, or if no slash is found, a slash
 		is appended to `path`. In particular, this applies to the empty String
 		is appended to `path`. In particular, this applies to the empty String
 		"".
 		"".
-		
+
 		If `path` is null, the result is unspecified.
 		If `path` is null, the result is unspecified.
 	**/
 	**/
 	public static function addTrailingSlash( path : String ) : String {
 	public static function addTrailingSlash( path : String ) : String {
@@ -197,15 +246,15 @@ class Path {
 			else path;
 			else path;
 		}
 		}
 	}
 	}
-	
+
 	/**
 	/**
 		Removes trailing slashes from `path`.
 		Removes trailing slashes from `path`.
-		
+
 		If `path` does not end with a `/` or `\`, `path` is returned unchanged.
 		If `path` does not end with a `/` or `\`, `path` is returned unchanged.
-		
+
 		Otherwise the substring of `path` excluding the trailing slashes or
 		Otherwise the substring of `path` excluding the trailing slashes or
 		backslashes is returned.
 		backslashes is returned.
-		
+
 		If `path` is null, the result is unspecified.
 		If `path` is null, the result is unspecified.
 	**/
 	**/
 	@:require(haxe_ver >= 3.01)
 	@:require(haxe_ver >= 3.01)

+ 9 - 0
tests/unit/unitstd/haxe/io/Path.unit.hx

@@ -60,6 +60,15 @@ haxe.io.Path.withExtension(path2, "foo") == "/dir1/dir.with.dots\\file.foo";
 haxe.io.Path.withExtension(path3, "foo") == ".foo";
 haxe.io.Path.withExtension(path3, "foo") == ".foo";
 haxe.io.Path.withExtension(path4, "foo") == "/dir/.foo";
 haxe.io.Path.withExtension(path4, "foo") == "/dir/.foo";
 
 
+// normalize
+haxe.io.Path.normalize("dir1/dir2/../dir3") == "dir1/dir3";
+haxe.io.Path.normalize("/dir1/dir2/../../test.foo") == "/test.foo";
+haxe.io.Path.normalize("dir1/dir2/dir3/dir4/../../../dir5") == "dir1/dir5";
+
+// join
+haxe.io.Path.join("dir1/dir2", "dir3/dir4") == "dir1/dir2/dir3/dir4";
+haxe.io.Path.join("dir1/dir2/bad_dir/", "../dir3/dir4") == "dir1/dir2/dir3/dir4";
+
 // addTrailingSlash
 // addTrailingSlash
 haxe.io.Path.addTrailingSlash("") == "/";
 haxe.io.Path.addTrailingSlash("") == "/";
 haxe.io.Path.addTrailingSlash("a") == "a/";
 haxe.io.Path.addTrailingSlash("a") == "a/";