Paths

Path values represent filesystem paths. They are first-class objects (not strings) with properties and methods for manipulation. Paths are created from literals prefixed with @.

Literals

@./config.json                   // relative to current file
@~/lib/utils.pars                // relative to project root
Prefix Resolves relative to
@./ Current file's directory
@~/ Project root

⚠️ @~/ means the project root, not the user's home directory. This is different from shell conventions.

Interpolated Paths

Use @(...) with {expr} placeholders for dynamic paths:

let name = "config"
@(./data/{name}.json)            // ./data/config.json

let id = 42
@(./users/{id}/profile.json)     // ./users/42/profile.json

path() Builtin

Create a path from a string β€” useful when the path is fully dynamic:

let p = path("./relative/path")

Prefer literals for static paths β€” they're checked at parse time.

Properties

Property Type Description
.segments array Path segments as array of strings
.filename string Last segment (file or directory name)
.extension string File extension (without leading dot)
.stem string Filename without extension
.parent path Parent directory as a path value
.absolute boolean Whether the path is absolute
.suffixes array All extensions as array (e.g., ["tar", "gz"])
let p = @./users/123/profile.json
p.filename                       // "profile.json"
p.extension                      // "json"
p.stem                           // "profile"
p.segments                       // [".", "users", "123", "profile.json"]
p.parent.filename                // "123"

Methods

.isAbsolute() / .isRelative()

let rel = @./config.json
rel.isAbsolute()                 // false
rel.isRelative()                 // true

.match(pattern)

Match against a route-style pattern. Returns a dictionary of captures or null:

let p = @./users/123/profile.json
p.match("/users/:id/:file")      // {id: "123", file: "profile.json"}
p.match("/products/:id")         // null

Pattern syntax: :param matches a single segment, *splat matches multiple.

.toURL(prefix)

Convert to a URL string with a prefix:

let p = @./images/logo.png
p.toURL("https://cdn.example.com")
// "https://cdn.example.com/images/logo.png"

.public()

Get the public web-serving URL for this path:

let p = @./assets/style.css
p.public()                       // "/assets/style.css"

.toDict() / .inspect()

let p = @./config.json
p.toDict()                       // {segments: [".", "config.json"], absolute: false}
p.inspect()                      // includes __type: "path"

Path Arithmetic

Use + or / to join path segments:

let base = @./data
let full = base + "users.json"
// ./data/users.json

Paths as File Handle Sources

Paths are the primary argument to file handle constructors:

let config <== PLN(@./config.pln)        // Parsley config (preserves dates, money, paths)
let data <== JSON(@./api-cache.json)     // JSON from external API
let lines <== lines(@./todo.txt)
"output" ==> text(@./result.txt)

Tip: Use PLN for Parsley configuration filesβ€”it preserves types like dates, money, and paths. Use JSON for data exchanged with external systems.

See File I/O for the full file operations reference.

Paths in Import Statements

Path literals are used for module imports:

import @./utils.pars             // relative import
import @~/lib/helpers.pars       // project root import
import @std/math                 // stdlib (not a filesystem path)

See Modules for import details.

Key Differences from Other Languages

See Also