Module
LinkThe module exports immutable normalized relative paths. Path.from constructs a path from text. Members inspect components or produce another normalized Path without accessing the filesystem.
Why
LinkA normalized representation gives path composition one meaning before the host applies filesystem permissions and platform rules.
Availability
LinkImport std.path in language mode 5.21. The current compiler selects std/path.tpz for this language mode. Availability in other released editions and inclusion in each installed distribution are Pending.
Exported types
Linkexport type Path = Path
Type members keep the compiler-owned type name shown in their declarations. Importing a module does not create a new type identity.
Public API
LinkPending contracts
LinkConstruct normalized paths with Path.from
LinkConstruct normalized paths with Path.from
Path.from(text) is the constructor for normalized relative paths and returns Result<Path, string>.
Path.from normalizes path separators and removes empty and dot components. Parent components must stay within the relative root. A path reduced to no components is represented by a dot.
Empty text, NUL, absolute paths, and parent traversal beyond the relative root return Err. These input failures are values that a caller can handle.
A leading slash or backslash returns Err. Text that starts with one ASCII character followed immediately by a colon returns Err.
Path.cwdRelative and Path.project are absent. A Path value already satisfies normalization and has no normalize member.
Path operations inspect text without accessing the filesystem. Constructing a Path does not establish that its target exists or is accessible.
Why
One constructor gives relative path text one interpretation. Normalization is a Path invariant, so a separate identity operation gives the same value a second spelling.
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 317 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 423 - compiler/crates/topaz_self_frontend/topaz/checker/expression_core.tpz at
271329b482bc· 1391 -
topaz.stdlib.contract.path-fromatworking-tree - topaz.decision.path-from.1 at
topaz.decisi
Construct a normalized path
Linkimport std.path { Path }import std.testimport std.iolet chapter = test.assertOk(Path.from("chapters/./draft/../main.tpz"))io.writeLine(chapter.toString())
chapters/main.tpz
Expected result
Expected result
Execution completes. Exit code 0.
chapters/main.tpz
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 317 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 423 - compiler/crates/topaz_self_frontend/topaz/checker/expression_core.tpz at
271329b482bc· 1391 -
topaz.stdlib.contract.path-fromatworking-tree - topaz.decision.path-from.1 at
topaz.decisi
Reject a path that escapes its relative root
Linkimport std.path { Path }import std.iomatch (Path.from("../chapter.tpz")) {case Err(_) => io.writeLine("outside root rejected")case Ok(_) => io.writeLine("accepted")}
outside root rejected
Expected result
Expected result
Execution completes. Exit code 0.
outside root rejected
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 317 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 423 - compiler/crates/topaz_self_frontend/topaz/checker/expression_core.tpz at
271329b482bc· 1391 -
topaz.stdlib.contract.path-fromatworking-tree - topaz.decision.path-from.1 at
topaz.decisi
Reject Path.cwdRelative
Linkimport std.path { Path }let value = Path.cwdRelative("chapter.tpz")
No stdout.
Expected result
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 317 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 423 - compiler/crates/topaz_self_frontend/topaz/checker/expression_core.tpz at
271329b482bc· 1391 -
topaz.stdlib.contract.path-fromatworking-tree - topaz.decision.path-from.1 at
topaz.decisi
Reject Path.project
Linkimport std.path { Path }let value = Path.project("chapter.tpz")
No stdout.
Expected result
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 317 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 423 - compiler/crates/topaz_self_frontend/topaz/checker/expression_core.tpz at
271329b482bc· 1391 -
topaz.stdlib.contract.path-fromatworking-tree - topaz.decision.path-from.1 at
topaz.decisi
Reject Path.normalize
Linkimport std.path { Path }function inspect(path: Path) -> () {let value = path.normalize()return ()}
No stdout.
Expected result
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 317 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 423 - compiler/crates/topaz_self_frontend/topaz/checker/expression_core.tpz at
271329b482bc· 1391 -
topaz.stdlib.contract.path-fromatworking-tree - topaz.decision.path-from.1 at
topaz.decisi
Distinguish rejected ASCII prefixes from relative path text
Linkimport std.path { Path }import std.testimport std.iotest.assertErr(Path.from("a:"))test.assertErr(Path.from("1:"))test.assertErr(Path.from("!:"))io.writeLine(test.assertOk(Path.from("aa:")).toString())io.writeLine(test.assertOk(Path.from("é:")).toString())io.writeLine(test.assertOk(Path.from("가:")).toString())
aa: é: 가:
Expected result
Expected result
Execution completes. Exit code 0.
aa:é:가:
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 317 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
271329b482bc· 423 - compiler/crates/topaz_self_frontend/topaz/checker/expression_core.tpz at
271329b482bc· 1391 -
topaz.stdlib.contract.path-fromatworking-tree - topaz.decision.path-from.1 at
topaz.decisi
Diagnostics
LinkInspect and transform normalized paths
LinkInspect and transform normalized paths
A Path is immutable normalized relative text. Every member evaluates its receiver and arguments once in ordinary call order. Members perform no host access and leave the receiver unchanged on success and failure.
to returns the exact normalized representation. Separators are forward slashes and the relative root is a dot. Constructing a Path from that text returns the same representation.
join accepts nonempty relative child text. It rejects NUL, a leading separator, and a colon immediately after one ASCII character before combining the child with the receiver. Both slash forms are separators. Parent components remove preceding components from the combined path and return Err when none remain to remove.
Joining a child may reach the relative root but may not cross it. A dot child preserves the receiver. Invalid child text returns Err containing an error string without producing a Path. Error text identifies Path.join and the invalid condition.
parent removes the final component. For a one component path it returns Some containing the dot root. The relative root has no parent and returns None().
file returns the final component without any preceding separator. The relative root returns None(). These results describe text and do not establish whether the path identifies a file or directory.
extension returns the text after the final dot in the file name, provided that dot is not its first character. A leading dot alone does not introduce an extension. A final dot returns Some(""). A name without such a dot and the relative root return None().
with replaces the final extension or appends one when it is absent. The argument supplies the suffix without a leading dot. An empty argument removes an existing suffix and its separating dot. A leading dot, either separator, or NUL in the argument returns Err.
with preserves a leading dot that belongs to the file name. It returns Err when the receiver is the relative root because that path has no file name. A successful replacement is normalized with the same rules as Path.from.
Path validation describes lexical text. Host operations may reject an otherwise valid Path because of platform naming rules, permissions, or capability restrictions. A Path does not establish filesystem existence or prevent a symbolic link from resolving elsewhere.
Why
One normalized representation makes composition predictable. Parent and extension queries describe components without consulting host state. A suffix has one accepted spelling, and joining validates the child before its leading separator can disappear inside the combined text.
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Join relative components without changing the receiver
Linkimport std.path { Path }import std.testimport std.iolet base = test.assertOk(Path.from("chapters/draft"))let child = test.assertOk(base.join("../final/./main.tpz"))io.writeLine(base.toString())io.writeLine(child.toString())io.writeLine(test.assertOk(base.join("../..")).toString())io.writeLine(test.assertOk(base.join(".")).toString())
chapters/draft chapters/final/main.tpz . chapters/draft
Expected result
Expected result
Execution completes. Exit code 0.
chapters/draftchapters/final/main.tpz.chapters/draft
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Reject invalid child text before joining
Linkimport std.path { Path }import std.testimport std.iolet base = test.assertOk(Path.from("chapters"))for child in (["", "/outside", "C:/outside", "../../outside"]) {match (base.join(child)) {case Err(_) => io.writeLine("rejected")case Ok(_) => io.writeLine("accepted")}}io.writeLine(base.toString())
rejected rejected rejected rejected chapters
Expected result
Expected result
Execution completes. Exit code 0.
rejectedrejectedrejectedrejectedchapters
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Inspect the final component and the relative root
Linkimport std.path { Path }import std.testimport std.iolet file = test.assertOk(Path.from("chapters/main.tpz"))io.writeLine(test.assertSome(file.parent()).toString())io.writeLine(test.assertSome(file.fileName()))io.writeLine(test.assertSome(file.extension()))let root = test.assertOk(Path.from("."))test.assertNone(root.parent())test.assertNone(root.fileName())test.assertNone(root.extension())io.writeLine(root.toString())
chapters main.tpz tpz .
Expected result
Expected result
Execution completes. Exit code 0.
chaptersmain.tpztpz.
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Keep the relative root as the parent of one component
Linkimport std.path { Path }import std.testimport std.iolet file = test.assertOk(Path.from("main.tpz"))match (file.parent()) {case Some(parent) => io.writeLine(parent.toString())case None() => io.writeLine("missing")}
.
Expected result
Expected result
Execution completes. Exit code 0.
.
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Distinguish an absent extension from an empty extension
Linkimport std.path { Path }import std.testimport std.iofor name in (["README", ".env", ".env.local", "archive.tar.gz", "trailing."]) {let file = test.assertOk(Path.from(name))match (file.extension()) {case Some(extension) => io.writeLine("present [{extension}]")case None() => io.writeLine("absent")}}
absent absent present [local] present [gz] present []
Expected result
Expected result
Execution completes. Exit code 0.
absentabsentpresent [local]present [gz]present []
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Replace and remove a final extension
Linkimport std.path { Path }import std.testimport std.iolet file = test.assertOk(Path.from("chapters/main.tpz"))io.writeLine(test.assertOk(file.withExtension("pdf")).toString())io.writeLine(test.assertOk(file.withExtension("")).toString())io.writeLine(file.toString())
chapters/main.pdf chapters/main chapters/main.tpz
Expected result
Expected result
Execution completes. Exit code 0.
chapters/main.pdfchapters/mainchapters/main.tpz
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Preserve the name of a file that starts with a dot
Linkimport std.path { Path }import std.testimport std.iolet file = test.assertOk(Path.from(".env"))io.writeLine(test.assertOk(file.withExtension("local")).toString())io.writeLine(test.assertOk(file.withExtension("")).toString())
.env.local .env
Expected result
Expected result
Execution completes. Exit code 0.
.env.local.env
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi
Reject a second suffix spelling and a path without a file name
Linkimport std.path { Path }import std.testimport std.iolet file = test.assertOk(Path.from("chapter.txt"))for extension in ([".pdf", "pdf/extra", "pdf\\extra"]) {match (file.withExtension(extension)) {case Err(_) => io.writeLine("rejected")case Ok(_) => io.writeLine("accepted")}}let root = test.assertOk(Path.from("."))match (root.withExtension("pdf")) {case Err(_) => io.writeLine("root rejected")case Ok(_) => io.writeLine("root accepted")}
rejected rejected rejected root rejected
Expected result
Expected result
Execution completes. Exit code 0.
rejectedrejectedrejectedroot rejected
Source evidence
- compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 260 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 341 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 357 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 370 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 382 - compiler/crates/topaz_value/src/value/builtins/path_regex_url.rs at
912a5e86e1f9· 397 -
topaz.stdlib.contract.path-operationsatworking-tree - topaz.decision.path-components.1 at
topaz.decisi