grain icon indicating copy to clipboard operation
grain copied to clipboard

stdlib: add path libary

Open spotandjake opened this issue 1 year ago • 9 comments

Add a libary for working with file paths to help once #211

spotandjake avatar Jul 30 '22 05:07 spotandjake

It would probably be better to do this before/with #211 so there won't need to be any breaking changes.

ospencer avatar Jul 30 '22 17:07 ospencer

Possible API, though instead of using strings it might be worth considering using a record to store the path and having a path.parse to convert the string into a record for type safety that way the api should only error on parsing and not on actual manipulations, would also possibly allow for figuring out the seperator and supporting posixs and windows quickly as we cant get the system type from wasi easily so the best way to figure it out would be the seperator probably.

// Removes:  ../ and ./ from the path
normalize: (String) => String
// Join: Joins the paths in the strings together
join: (List<String>) => String
// relative: Makes one path relative to another
relative: (String, String) => String
// toAbsolute: Makes the path absolute, i dont know if we can get the base system path so we might need to make the path absolute relative to the base path if possible
toAbsolute: (String) => String
// Desconstruct: Breaks the path into segments for example /home/user/ would be converted into [ home, user ]
Deconstruct: (String) => List<String>
// getExension: Gets the file extension from a path if there is one
getExension: (String) => Option<String>
/// getName: Gets the file name from the path if there is one
getName: (String) => Option<String>
// getDirectory: Returns The Current Directory
getDirectory: (String) => String
// getPath: Gets The Current Path
getPath: (String) => String

I might have missed some utility functions here but this would probably be a good start

spotandjake avatar Jul 30 '22 18:07 spotandjake

I'm 100% against using string types for file paths. They have caused so many miserable bugs in the compiler.

phated avatar Jul 30 '22 20:07 phated

I'm 100% against using string types for file paths. They have caused so many miserable bugs in the compiler.

so then the api might look something like this I guess

exception FilePathException
  0 -> "Invalid Path"
record FilePath {
  path: String, // possibly store it as segments: List<String> 
  fileName: String,
  fileExtension: String,
}
// parse: Parses A String Into A File Path, it might make sense to take in a base path here as well for making things absolute or a system type like posix or win32 for dealing with separators and stuff, would be nice if we could autodetect but that isn't possible in all cases
parse: (String) => Result<FilePath, FilePathException>
// toString: converts a file path into a string
toString: (FilePath) => String
// Removes:  ../ and ./ from the path
normalize: (FilePath) => FilePath
// Join: Joins the paths in the strings together
join: (List<FilePath>) => FilePath
// relative: Makes one path relative to another
relative: (FilePath, FilePath) => FilePath
// toAbsolute: Makes the path absolute, i dont know if we can get the base system path so we might need to make the path absolute relative to the base path if possible
toAbsolute: (FilePath) => FilePath
// Desconstruct: Breaks the path into segments for example /home/user/ would be converted into [ home, user ]
Deconstruct: (FilePath) => List<String>

// setExtension:sets the file extension for a path, I don't know what we want to happen if there is no file name
getExtension: (String, FilePath) => FilePath
/// setName: Sets the file name of a path
setName: (String, FilePath) => FilePath
// setDirectory: Sets the directory of the path, i.e the folder the path is in so setDirectory("user", Path.parse("/home/user/documents/file.ext")!) would return /home/user/user/file.ext
setDirectory: (String, FilePath) => FilePath
// setPath: Sets the current Path
setPath: (FilePath, FilePath) => FilePath

// getExtension: Gets the file extension from a path if there is one
getExtension: (FilePath) => Option<String>
/// getName: Gets the file name from the path if there is one
getName: (FilePath) => Option<String>
// getDirectory: Returns The Current Directory
getDirectory: (FilePath) => String
// getPath: Gets The Current Path
getPath: (FilePath) => FilePath

// Possible Additions
// getHash: Hashes the absolute filePath might be useful for comparison
getHash: (FilePath) => String

If a path type is used it would make sense to write this before #211 so 211 could accept the filePaths the downside to this is either you have to toString it for reading files or parse it for reading files but the type safety is worth it.

spotandjake avatar Jul 30 '22 20:07 spotandjake

You probably want to go look at ReasonNative's Fp library. They encode file paths interestingly.

phated avatar Jul 30 '22 20:07 phated

How should this library handle differences between POSIX/Windows paths? Some possible options I thought of:

  • Enforce POSIX-like paths when there is a difference between Windows/POSIX e.g. forcing forward slash delimiters (this appears to be what Fp does in most cases, for example)
  • Use the operating system running the code to determine which to use (is it even possible to get this info with WASI?)
  • Distinguishing between the two explicitly e.g. having ...Windows and ...Posix versions of functions when relevant (python takes this "explicit" approach in pathlib for example). This approach could also allow paths to be strongly typed by platform, similarly to how Fp types absolute vs. relative paths (although I'm not sure how useful that would be).

Note: the second and third options aren't necessarily mutually exclusive, and both could be used simultaneously.

alex-snezhko avatar Oct 12 '22 01:10 alex-snezhko

I did some research and dit doesnt look to be possible to get the platform type from the operating systtem also that wouldnt make sense in a web enviroment.

spotandjake avatar Oct 12 '22 01:10 spotandjake

I think I'd lean towards enforcing POSIX-like paths.

ospencer avatar Oct 12 '22 21:10 ospencer

I think I'd lean towards enforcing POSIX-like paths.

I think this would make sense would it be possible though maybe to add toWindows path and fromWindows path the conversion shouldn't be that hard realistically and that might allow more power to users when working on apps that are cross platform it would be nice if could handle both paths though as ideally there would probably be a path.parse and a path.join and everything else would work on some sort of internal representation so it probably wouldn't matter what the path type is beyond the parse and join where you could then deal with it depending on the os.

spotandjake avatar Oct 12 '22 21:10 spotandjake