From d43d35d266fa50ec1c7370a59da63bb56444e728 Mon Sep 17 00:00:00 2001 From: haithium <128622475+haithium@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:55:30 +0000 Subject: [PATCH] chore(docs): auto-generate docs --- docs/src/modules/fs.md | 531 +++++++++++++++++++++++++++++++- docs/src/modules/is.md | 25 +- docs/src/modules/keyword.md | 4 +- docs/src/modules/list.md | 158 +++++----- docs/src/modules/ntpath.md | 4 +- docs/src/modules/operator.md | 4 +- docs/src/modules/path.md | 548 ++++++++++++++++++++++++++++++--- docs/src/modules/posixpath.md | 4 +- docs/src/modules/repr.md | 4 +- docs/src/modules/runtime.md | 4 +- docs/src/modules/set.md | 198 +++++++----- docs/src/modules/str.md | 5 +- docs/src/modules/stringcase.md | 4 +- docs/src/modules/tbl.md | 103 +++++-- docs/src/modules/template.md | 4 +- docs/src/modules/utils.md | 143 ++++++++- docs/src/modules/validate.md | 249 +++++++++------ 17 files changed, 1658 insertions(+), 334 deletions(-) diff --git a/docs/src/modules/fs.md b/docs/src/modules/fs.md index 68facb7..e5cd6c0 100644 --- a/docs/src/modules/fs.md +++ b/docs/src/modules/fs.md @@ -1,10 +1,10 @@ --- -description: "Filesystem I/O and metadata operations." +description: "Filesystem I/O, metadata, and filesystem path operations." --- # `fs` -Filesystem I/O and metadata operations. +Filesystem I/O, metadata, and filesystem path operations. ## Usage @@ -12,21 +12,520 @@ Filesystem I/O and metadata operations. fs = require "mods.fs" fs.mkdir("tmp/cache/app", true) +fs.write_text("tmp/cache/app/data.txt", "hello") +print(fs.read_text("tmp/cache/app/data.txt")) --> "hello" ``` ## Functions -| Function | Description | -| ---------- | -------------------------------------------------- | -| `getcwd` | Alias of `lfs.currentdir` | -| `isblock` | Alias of [`mods.is.block`](/modules/is#fn-block) | -| `ischar` | Alias of [`mods.is.char`](/modules/is#fn-char) | -| `isdevice` | Alias of [`mods.is.device`](/modules/is#fn-device) | -| `isdir` | Alias of [`mods.is.dir`](/modules/is#fn-dir) | -| `isfifo` | Alias of [`mods.is.fifo`](/modules/is#fn-fifo) | -| `isfile` | Alias of [`mods.is.file`](/modules/is#fn-file) | -| `islink` | Alias of [`mods.is.link`](/modules/is#fn-link) | -| `issocket` | Alias of [`mods.is.socket`](/modules/is#fn-socket) | -| `lstat` | Alias of `lfs.symlinkattributes` | -| `rmdir` | Alias of `lfs.rmdir` | -| `stat` | Alias of `lfs.attributes` | +**Reading**: + +| Function | Description | +| ------------------------------------- | -------------------------------------- | +| [`read_bytes(path)`](#fn-read-bytes) | Read full file in binary mode. | +| [`read_text(path)`](#fn-read-text) | Read full file in text mode. | +| [`dir(path, opts?)`](#fn-dir) | Iterator over items in `path`. | +| [`listdir(path, opts?)`](#fn-listdir) | Return direct children of a directory. | + +**Writing**: + +| Function | Description | +| -------------------------------------------- | ----------------------------------------------------------------------------- | +| [`write_bytes(path, data)`](#fn-write-bytes) | Write full file in binary mode. | +| [`write_text(path, data)`](#fn-write-text) | Write full file in text mode. | +| [`touch(path)`](#fn-touch) | Create file if missing without truncating, or update timestamps if it exists. | +| [`rename(oldname, newname)`](#fn-rename) | Rename or move a filesystem entry. | +| [`rm(path, recursive?)`](#fn-rm) | Remove a filesystem entry, or a directory tree when `recursive` is `true`. | +| [`mkdir(path, parents?)`](#fn-mkdir) | Create a directory. | +| [`cp(src, dst)`](#fn-cp) | Copy a file or directory tree. | + +**Metadata**: + +| Function | Description | +| ------------------------------------------ | ---------------------------------------------------------------------------------- | +| [`getsize(path)`](#fn-getsize) | Return file size in bytes. | +| [`getatime(path)`](#fn-getatime) | Return last access time. | +| [`getmtime(path)`](#fn-getmtime) | Return last modification time. | +| [`getctime(path)`](#fn-getctime) | Return metadata change time. | +| [`lstat(path)`](#fn-lstat) | Return symlink-aware file attributes. | +| [`stat(path)`](#fn-stat) | Return file attributes. | +| [`samefile(path_a, path_b)`](#fn-samefile) | Return whether two paths refer to the same file, or `nil` and an error on failure. | + +**Existence Checks**: + +| Function | Description | +| ------------------------------ | ------------------------------------------------------------ | +| [`exists(path)`](#fn-exists) | Return `true` when a path exists. | +| [`lexists(path)`](#fn-lexists) | Return `true` when a path exists without following symlinks. | + +### Reading + + + +#### `read_bytes(path)` + +Read full file in binary mode. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `body` (`string?`): File contents read in binary mode, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.read_bytes("README.md") +``` + + + +#### `read_text(path)` + +Read full file in text mode. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `body` (`string?`): File contents read in text mode, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.read_text("README.md") +``` + + + +#### `dir(path, opts?)` + +Iterator over items in `path`. + +**Parameters**: + +- `path` (`string`): Input path. +- `opts?` (`{hidden?:boolean,`): recursive?:boolean, follow_links?:boolean, + type?:string} Optional traversal options. + +**Return**: + +- `prev?:string):basename:string?,` (`(fun(state:table,`): + type:"file"|"directory"|"link"|"fifo"|"socket"|"char"|"block"|"unknown"?)? + iterator Iterator, or `nil` on failure. +- `state` (`table|string`): Iterator state on success, or error message on + failure. + +**Example**: + +```lua +for name, type in fs.dir(path.cwd(), { recursive = true }) do + print(name, type) +end +``` + + + +#### `listdir(path, opts?)` + +Return direct children of a directory. + +**Parameters**: + +- `path` (`string`): Input path. +- `opts?` (`{hidden?:boolean,`): recursive?:boolean, follow_links?:boolean, + type?:string} Optional traversal options. + +**Return**: + +- `paths` (`mods.List?`): Direct child paths. +- `err` (`string?`): Error message when traversal setup fails. + +**Example**: + +```lua +fs.listdir("src") +``` + +### Writing + + + +#### `write_bytes(path, data)` + +Write full file in binary mode. + +**Parameters**: + +- `path` (`string`): Input path. +- `data` (`string`): Input data. + +**Return**: + +- `written` (`true?`): `true` when writing succeeds, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.write_bytes("tmp.bin", "abc") --> true, nil +``` + + + +#### `write_text(path, data)` + +Write full file in text mode. + +**Parameters**: + +- `path` (`string`): Input path. +- `data` (`string`): Input data. + +**Return**: + +- `written` (`true?`): `true` when writing succeeds, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.write_text("tmp.txt", "abc") --> true, nil +``` + + + +#### `touch(path)` + +Create file if missing without truncating, or update timestamps if it exists. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `touched` (`true?`): `true` when the file exists after touch, or `nil` on + failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.touch("tmp.txt") --> true, nil +``` + + + +#### `rename(oldname, newname)` + +Rename or move a filesystem entry. + +**Parameters**: + +- `oldname` (`string`): Existing path. +- `newname` (`string`): Replacement path. + +**Return**: + +- `renamed` (`true?`): `true` when the rename succeeds, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.rename("old.txt", "new.txt") +``` + +> [!NOTE] This is an alias for `os.rename`. + + + +#### `rm(path, recursive?)` + +Remove a filesystem entry, or a directory tree when `recursive` is `true`. + +**Parameters**: + +- `path` (`string`): Input path. +- `recursive?` (`boolean`): Remove a directory tree recursively when `true`. + +**Return**: + +- `removed` (`true?`): `true` when removal succeeds, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.rm("tmp.txt") --> true, nil +fs.rm("tmp/cache", true) --> true, nil +``` + + + +#### `mkdir(path, parents?)` + +Create a directory. + +**Parameters**: + +- `path` (`string`): Input path. +- `parents?` (`boolean`): Create missing parent directories when `true`. + +**Return**: + +- `created` (`true?`): `true` when directory creation succeeds, or `nil` on + failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.mkdir("tmp/a/b", true) +``` + + + +#### `cp(src, dst)` + +Copy a file or directory tree. + +**Parameters**: + +- `src` (`string`): Source path. +- `dst` (`string`): Destination path. + +**Return**: + +- `copied` (`true?`): `true` when copying succeeds, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.cp("a.txt", "b.txt") +fs.cp("src", "backup/src") +``` + +### Metadata + + + +#### `getsize(path)` + +Return file size in bytes. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `size` (`integer?`): File size in bytes. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.getsize("README.md") --> 1234 +``` + + + +#### `getatime(path)` + +Return last access time. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `timestamp` (`number?`): Access time (seconds since epoch). +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.getatime("README.md") --> 1712345678 +``` + + + +#### `getmtime(path)` + +Return last modification time. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `timestamp` (`number?`): Modification time (seconds since epoch). +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.getmtime("README.md") --> 1712345678 +``` + + + +#### `getctime(path)` + +Return metadata change time. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `timestamp` (`number?`): Change time (seconds since epoch). +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.getctime("README.md") --> 1712345678 +``` + + + +#### `lstat(path)` + +Return symlink-aware file attributes. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `attrs` (`LuaFileSystem.Attributes?`): Symlink-aware attributes, or `nil` on + failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.lstat("README.md") +``` + + + +#### `stat(path)` + +Return file attributes. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `attrs` + (`string|integer|LuaFileSystem.AttributeMode|LuaFileSystem.Attributes?`): File + attributes, or `nil` on failure. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.stat("README.md") +``` + + + +#### `samefile(path_a, path_b)` + +Return whether two paths refer to the same file, or `nil` and an error on +failure. + +**Parameters**: + +- `path_a` (`string`): Input path. +- `path_b` (`string`): Input path. + +**Return**: + +- `isSameFile` (`boolean?`): True when both paths refer to the same file. +- `errmsg` (`string?`): Error message when the check fails. +- `errcode` (`integer?`): OS error code when available. + +**Example**: + +```lua +fs.samefile("README.md", "README.md") --> true +``` + +### Existence Checks + + + +#### `exists(path)` + +Return `true` when a path exists. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `exists` (`boolean`): True when the path exists. + +**Example**: + +```lua +fs.exists("README.md") --> true +``` + +> [!NOTE] Broken symlinks return `false`. + + + +#### `lexists(path)` + +Return `true` when a path exists without following symlinks. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `exists` (`boolean`): True when the path or symlink entry exists. + +**Example**: + +```lua +fs.lexists("README.md") --> true +``` + +> [!NOTE] Broken symlinks return `true`. diff --git a/docs/src/modules/is.md b/docs/src/modules/is.md index 8a3fa47..7c89073 100644 --- a/docs/src/modules/is.md +++ b/docs/src/modules/is.md @@ -67,6 +67,7 @@ is("hello", "STRING") --> true | Function | Description | | ------------------------- | ------------------------------------------------------------ | +| [`path(v)`](#fn-path) | Returns `true` when `v` is a valid filesystem path. | | [`block(v)`](#fn-block) | Returns `true` when `v` is a block device path. | | [`char(v)`](#fn-char) | Returns `true` when `v` is a character device path. | | [`device(v)`](#fn-device) | Returns `true` when `v` is a block or character device path. | @@ -368,7 +369,29 @@ Filesystem path type checks. > > Path checks require **LuaFileSystem** > ([`lfs`](https://github.com/lunarmodules/luafilesystem)) and raise an error if -> it is not installed. +> it is not installed. + +#### `path(v)` + +Returns `true` when `v` is a valid filesystem path. + +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `isPath` (`boolean`): Whether the check succeeds. + +**Example**: + +```lua +is.path("README.md") +``` + +> [!NOTE] Returns `true` for broken symlinks. + + #### `block(v)` diff --git a/docs/src/modules/keyword.md b/docs/src/modules/keyword.md index 94b5a11..97a0aaf 100644 --- a/docs/src/modules/keyword.md +++ b/docs/src/modules/keyword.md @@ -1,10 +1,10 @@ --- -description: "Lua keyword helpers." +description: "Helpers for Lua keywords and identifiers." --- # `keyword` -Lua keyword helpers. +Helpers for Lua keywords and identifiers. ## Usage diff --git a/docs/src/modules/list.md b/docs/src/modules/list.md index 1ec6f76..3ef666d 100644 --- a/docs/src/modules/list.md +++ b/docs/src/modules/list.md @@ -1,13 +1,11 @@ --- description: - "A list class providing common operations to create, modify, and query - sequences of values." + "A list class for creating, transforming, and querying sequences of values." --- # `List` -A list class providing common operations to create, modify, and query sequences -of values. +A list class for creating, transforming, and querying sequences of values. ## Usage @@ -31,8 +29,8 @@ print(ls:index("b")) --> 2 | Function | Description | | -------------------------- | ------------------------------------------------- | -| [`all(pred)`](#fn-all) | Return true if all values match the predicate. | -| [`any(pred)`](#fn-any) | Return true if any value matches the predicate. | +| [`all(pred)`](#fn-all) | Return `true` if all values match the predicate. | +| [`any(pred)`](#fn-any) | Return `true` if any value matches the predicate. | | [`equals(ls)`](#fn-equals) | Compare two lists using shallow element equality. | | [`lt(ls)`](#fn-lt) | Compare two lists lexicographically. | | [`le(ls)`](#fn-le) | Compare two lists lexicographically. | @@ -43,7 +41,7 @@ print(ls:index("b")) --> 2 | ------------------------------ | -------------------------------------------------------------------- | | [`append()`](#fn-append) | Append a value to the end of the list. | | [`clear()`](#fn-clear) | Remove all elements from the list. | -| [`extend(ls)`](#fn-extend) | Extend the list with another list. | +| [`extend(t)`](#fn-extend) | Extend the list with another list or set. | | [`extract(pred)`](#fn-extract) | Extract values matching the predicate and remove them from the list. | | [`insert(pos, v)`](#fn-insert) | Insert a value at the given position. | | [`insert(v)`](#fn-insert) | Append a value to the end of the list. | @@ -63,11 +61,12 @@ print(ls:index("b")) --> 2 | Function | Description | | -------------------------------- | ----------------------------------------------------------- | -| [`contains(v)`](#fn-contains) | Return true if the list contains the value. | +| [`contains(v)`](#fn-contains) | Return `true` if the list contains the value. | | [`count(v)`](#fn-count) | Count how many times a value appears. | | [`index(v)`](#fn-index) | Return the index of the first matching value. | | [`index_if(pred)`](#fn-index-if) | Return the index of the first value matching the predicate. | | [`len()`](#fn-len) | Return the number of elements in the list. | +| [`isempty()`](#fn-isempty) | Return whether the list has no elements. | **Access**: @@ -78,29 +77,29 @@ print(ls:index("b")) --> 2 **Transform**: -| Function | Description | -| -------------------------------------- | -------------------------------------------------------------------- | -| [`difference(ls)`](#fn-difference) | Return a new list with values not in the given list. | -| [`drop(n)`](#fn-drop) | Return a new list without the first n elements. | -| [`filter(pred)`](#fn-filter) | Return a new list with values matching the predicate. | -| [`flatten()`](#fn-flatten) | Flatten one level of nested lists. | -| [`foreach(fn)`](#fn-foreach) | Apply a function to each element (for side effects). | -| [`group_by(fn)`](#fn-group-by) | Group list values by a computed key. | -| [`intersection(ls)`](#fn-intersection) | Return values that are also present in the given list. | -| [`invert()`](#fn-invert) | Invert values to indices in a new table. | -| [`concat(sep?, i?, j?)`](#fn-concat) | Concatenate list values using Lua's native `table.concat` behavior. | -| [`join(sep?, quoted?)`](#fn-join) | Join list values into a string. | -| [`tostring()`](#fn-tostring) | Render the list to a string via the regular method form. | -| [`keypath()`](#fn-keypath) | Render list items as a table-access key path. | -| [`map(fn)`](#fn-map) | Return a new list by mapping each value. | -| [`mul(n)`](#fn-mul) | Return a new list repeated `n` times (list multiplication behavior). | -| [`reduce(fn, init?)`](#fn-reduce) | Reduce the list to a single value using an accumulator. | -| [`reverse()`](#fn-reverse) | Return a new list with items reversed. | -| [`toset()`](#fn-toset) | Convert the list to a set. | -| [`slice(i?, j?)`](#fn-slice) | Return a new list containing items from i to j (inclusive). | -| [`take(n)`](#fn-take) | Return the first n elements as a new list. | -| [`uniq()`](#fn-uniq) | Return a new list with duplicates removed (first occurrence kept). | -| [`zip(ls)`](#fn-zip) | Zip two lists into a list of 2-element tables. | +| Function | Description | +| ------------------------------------- | -------------------------------------------------------------------- | +| [`difference(t)`](#fn-difference) | Return a new list with values not in the given list or set. | +| [`drop(n)`](#fn-drop) | Return a new list without the first n elements. | +| [`filter(pred)`](#fn-filter) | Return a new list with values matching the predicate. | +| [`flatten()`](#fn-flatten) | Flatten one level of nested lists. | +| [`foreach(fn)`](#fn-foreach) | Apply a function to each element (for side effects). | +| [`group_by(fn)`](#fn-group-by) | Group list values by a computed key. | +| [`intersection(t)`](#fn-intersection) | Return values that are also present in the given list or set. | +| [`invert()`](#fn-invert) | Invert values to indices in a new table. | +| [`concat(sep?, i?, j?)`](#fn-concat) | Concatenate list values using Lua's native `table.concat` behavior. | +| [`join(sep?, quoted?)`](#fn-join) | Join list values into a string. | +| [`tostring()`](#fn-tostring) | Render the list to a string via the regular method form. | +| [`keypath()`](#fn-keypath) | Render list items as a table-access key path. | +| [`map(fn)`](#fn-map) | Return a new list by mapping each value. | +| [`mul(n)`](#fn-mul) | Return a new list repeated `n` times (list multiplication behavior). | +| [`reduce(fn, init?)`](#fn-reduce) | Reduce the list to a single value using an accumulator. | +| [`reverse()`](#fn-reverse) | Reverse the list in place. | +| [`toset()`](#fn-toset) | Convert the list to a set. | +| [`slice(i?, j?)`](#fn-slice) | Return a new list containing items from i to j (inclusive). | +| [`take(n)`](#fn-take) | Return the first n elements as a new list. | +| [`uniq()`](#fn-uniq) | Return a new list with duplicates removed (first occurrence kept). | +| [`zip(t)`](#fn-zip) | Zip two collections into a list of 2-element tables. | **Metamethods**: @@ -120,7 +119,7 @@ Boolean checks for list-wide conditions. #### `all(pred)` -Return true if all values match the predicate. +Return `true` if all values match the predicate. **Parameters**: @@ -145,7 +144,7 @@ ok = List({ 2, 4 }):all(is_even) --> true #### `any(pred)` -Return true if any value matches the predicate. +Return `true` if any value matches the predicate. **Parameters**: @@ -273,7 +272,7 @@ Append a value to the end of the list. **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: @@ -289,7 +288,7 @@ Remove all elements from the list. **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: @@ -299,22 +298,23 @@ ls = List({ "a", "b" }):clear() --> { } -#### `extend(ls)` +#### `extend(t)` -Extend the list with another list. +Extend the list with another list or set. **Parameters**: -- `ls` (`any[]`): List values. +- `t` (`mods.List|mods.Set|any[]`): Values to append. **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: ```lua -ls = List({ "a" }):extend({ "b", "c" }) --> { "a", "b", "c" } +ls = List({ "a" }):extend({ "b", "c" }) --> { "a", "b", "c" } +ls = List({ "a" }):extend(Set({ "b", "c" })) --> { "a", "b", "c" } ``` > [!NOTE] @@ -356,7 +356,7 @@ Insert a value at the given position. **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: @@ -376,7 +376,7 @@ Append a value to the end of the list. **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: @@ -434,7 +434,7 @@ Insert a value at the start of the list. **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: @@ -455,7 +455,7 @@ Remove the first matching value. **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: @@ -472,18 +472,23 @@ Sort the list in place. **Parameters**: -- `comp?` (`fun(a,b):boolean`): Optional comparison function (defaults to - `nil`). +- `comp?` (`fun(a:any,`): b:any):boolean Optional comparison function (defaults + to `nil`). **Return**: -- `self` (`T`): Current list instance. +- `self` (`T`): Current list. **Example**: ```lua ls = List({ 3, 1, 2 }) ls:sort() --> { 1, 2, 3 } + +words = List({ "ccc", "a", "bb" }) +words:sort(function(a, b) + return #a < #b +end) --> { "a", "bb", "ccc" } ``` ### Copying @@ -510,7 +515,7 @@ Read-only queries for membership, counts, and indices. #### `contains(v)` -Return true if the list contains the value. +Return `true` if the list contains the value. **Parameters**: @@ -607,6 +612,22 @@ n = List({ "a", "b", "c" }):len() --> 3 > > Uses Lua's `#` operator. + + +#### `isempty()` + +Return whether the list has no elements. + +**Return**: + +- `empty` (`boolean`): `true` when the list has no elements. + +**Example**: + +```lua +ok = List():isempty() --> true +``` + ### Access Direct element access helpers. @@ -646,13 +667,13 @@ v = List({ "a", "b" }):last() --> "b" Non-mutating transformations and derived-list operations. -#### `difference(ls)` +#### `difference(t)` -Return a new list with values not in the given list. +Return a new list with values not in the given list or set. **Parameters**: -- `ls` (`mods.List|any[]`): Other list value. +- `t` (`mods.List|mods.Set|any[]`): Values to remove. **Return**: @@ -770,13 +791,13 @@ g = List(words):group_by(string.len) --> { {"b"}, { "aa", "dd" }, { "ccc" } } -#### `intersection(ls)` +#### `intersection(t)` -Return values that are also present in the given list. +Return values that are also present in the given list or set. **Parameters**: -- `ls` (`mods.List|any[]`): Other list value. +- `t` (`mods.List|mods.Set|any[]`): Other list/set. **Return**: @@ -801,7 +822,7 @@ Invert values to indices in a new table. **Return**: -- `idxByValue` (`table`): Table mapping each value to its last index. +- `idxByValue` (`table`): Table mapping each value to its last index. **Example**: @@ -879,10 +900,6 @@ Render the list to a string via the regular method form. s = List({ "a", "b", 1 }):tostring() --> '{ "a", "b", 1 }' ``` -> [!NOTE] -> -> `tostring(list)` calls `list:tostring()`. - #### `keypath()` @@ -907,7 +924,7 @@ Return a new list by mapping each value. **Parameters**: -- `fn` (`fun(v):any`): Callback function. +- `fn` (`fun(value:T):any`): Callback function. **Return**: @@ -976,11 +993,11 @@ sum = List({ 1, 2, 3 }):reduce(add, 10) --> 16 #### `reverse()` -Return a new list with items reversed. +Reverse the list in place. **Return**: -- `ls` (`mods.List`): New list. +- `ls` (`mods.List`): Same list, reversed in place. **Example**: @@ -1071,13 +1088,13 @@ u = List({ "a", "b", "a", "c" }):uniq() --> { "a", "b", "c" } -#### `zip(ls)` +#### `zip(t)` -Zip two lists into a list of 2-element tables. +Zip two collections into a list of 2-element tables. **Parameters**: -- `ls` (`mods.List|any[]`): Other list value. +- `t` (`mods.List|mods.Set|any[]`): Values to pair with. **Return**: @@ -1086,12 +1103,13 @@ Zip two lists into a list of 2-element tables. **Example**: ```lua -z = List({ "a", "b" }):zip({ 1, 2 }) --> { {"a",1}, {"b",2} } +z = List({ "a", "b" }):zip({ 1, 2 }) --> { {"a",1}, {"b",2} } +z = List({ "a", "b" }):zip(Set({ 1, 2 })) --> { {"a",1}, {"b",2} } ``` > [!NOTE] > -> Length is the minimum of both lists. +> Length is the minimum of both tables' lengths. ### Metamethods @@ -1230,7 +1248,7 @@ left-hand list reference (`+`). **Return**: -- `self` (`mods.List|any[]`): Current list instance. +- `self` (`mods.List|any[]`): Current list. **Example**: @@ -1285,7 +1303,3 @@ Render the list to a string like `{ "a", "b", 1 }`. ```lua s = tostring(List({ "a", "b", 1 })) --> '{ "a", "b", 1 }' ``` - -> [!NOTE] -> -> `tostring(ls)` is equivalent to `:tostring()`. diff --git a/docs/src/modules/ntpath.md b/docs/src/modules/ntpath.md index a7c59d2..119a590 100644 --- a/docs/src/modules/ntpath.md +++ b/docs/src/modules/ntpath.md @@ -1,10 +1,10 @@ --- -description: "Path operations for Windows/NT-style paths." +description: "Windows/NT-style path operations." --- # `ntpath` -Path operations for Windows/NT-style paths. +Windows/NT-style path operations. > 💡Python `ntpath`-style behavior, ported to Lua. diff --git a/docs/src/modules/operator.md b/docs/src/modules/operator.md index 3e8aa8a..51951c7 100644 --- a/docs/src/modules/operator.md +++ b/docs/src/modules/operator.md @@ -1,10 +1,10 @@ --- -description: "Operator helpers as functions." +description: "Lua operators exposed as functions." --- # `operator` -Operator helpers as functions. +Lua operators exposed as functions. ## Usage diff --git a/docs/src/modules/path.md b/docs/src/modules/path.md index 2e866fa..fe5f7a5 100644 --- a/docs/src/modules/path.md +++ b/docs/src/modules/path.md @@ -1,10 +1,10 @@ --- -description: "Generic cross-platform path API." +description: "Cross-platform path operations with host-platform semantics." --- # `path` -Generic cross-platform path API. +Cross-platform path operations with host-platform semantics. ## Usage @@ -18,7 +18,7 @@ print(path.splitext("archive.tar.gz")) --> "archive.tar", ".gz" ## Functions -**Normalization & Predicates**: +**Normalization**: | Function | Description | | -------------------------------- | ---------------------------------------------------- | @@ -27,7 +27,7 @@ print(path.splitext("archive.tar.gz")) --> "archive.tar", ".gz" | [`normpath(path)`](#fn-normpath) | Normalize separators and dot segments. | | [`isabs(path)`](#fn-isabs) | Return `true` when `path` is absolute. | -**Path Decomposition**: +**Decomposition**: | Function | Description | | ------------------------------------ | -------------------------------------------------- | @@ -38,22 +38,61 @@ print(path.splitext("archive.tar.gz")) --> "archive.tar", ".gz" | [`basename(path)`](#fn-basename) | Return final path component. | | [`dirname(path)`](#fn-dirname) | Return directory portion of a path. | -**Environment Expand**: +**Environment**: -| Function | Description | -| ------------------------------------ | ---------------------------------------------- | -| [`expanduser(path)`](#fn-expanduser) | Expand `~` home segment when available. | -| [`home()`](#fn-home) | Return the current user's home directory path. | +| Function | Description | +| ------------------------------------ | ----------------------------------------------------------------------- | +| [`expanduser(path)`](#fn-expanduser) | Expand `~` home segment when available. | +| [`expandvars(path)`](#fn-expandvars) | Expand vars in a path (`$VAR`/`${VAR}` everywhere, `%VAR%` on Windows). | +| [`home()`](#fn-home) | Return the current user's home directory path. | +| [`cwd()`](#fn-cwd) | Return the current working directory path. | -**Derived Paths**: +**Derived**: -| Function | Description | -| -------------------------------------- | ------------------------------------------------ | -| [`abspath(path)`](#fn-abspath) | Return normalized absolute path. | -| [`relpath(path, start?)`](#fn-relpath) | Return `path` relative to optional `start` path. | -| [`commonpath(paths)`](#fn-commonpath) | Return longest common sub-path from a path list. | +| Function | Description | +| ----------------------------------------- | ------------------------------------------------ | +| [`abspath(path)`](#fn-abspath) | Return normalized absolute path. | +| [`relpath(path, start?)`](#fn-relpath) | Return `path` relative to optional `start` path. | +| [`commonpath(paths)`](#fn-commonpath) | Return longest common sub-path from a path list. | +| [`commonprefix(paths)`](#fn-commonprefix) | Return longest common leading string prefix. | -### Normalization & Predicates +**Anchors**: + +| Function | Description | +| ---------------------------- | ------------------------------------------- | +| [`drive(path)`](#fn-drive) | Return drive prefix when present. | +| [`root(path)`](#fn-root) | Return root separator segment when present. | +| [`anchor(path)`](#fn-anchor) | Return drive and root combined. | + +**Components**: + +| Function | Description | +| -------------------------------- | ------------------------------------------------------------- | +| [`parts(path)`](#fn-parts) | Split path into logical parts, including anchor when present. | +| [`stem(path)`](#fn-stem) | Return filename without its final suffix. | +| [`suffixes(path)`](#fn-suffixes) | Return all filename suffixes in order. | +| [`parents(path)`](#fn-parents) | Return logical parent paths from nearest to farthest. | + +**Relations**: + +| Function | Description | +| ------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| [`relative_to(path, other, walk_up?)`](#fn-relative-to) | Return `path` relative to `other`, or `nil` with an error when it is not under `other`. | +| [`is_relative_to(path, other)`](#fn-is-relative-to) | Return `true` when `path` is under `other`. | +| [`with_name(path, name)`](#fn-with-name) | Return a path with the final filename replaced. | +| [`with_stem(path, stem)`](#fn-with-stem) | Return a path with the final filename stem replaced. | +| [`with_suffix(path, suffix)`](#fn-with-suffix) | Return a path with the final filename suffix replaced. | + +**Conversions**: + +| Function | Description | +| ---------------------------------------------------- | --------------------------------------------------------------------------- | +| [`as_posix(path)`](#fn-as-posix) | Convert backslashes (`\`) to forward slashes (`/`). | +| [`as_uri(path)`](#fn-as-uri) | Convert a local path to a `file://` URI. | +| [`match(path, pattern, case_sensitive?)`](#fn-match) | Match a path against a glob-style pattern using only `*` and `?` wildcards. | +| [`from_uri(uri)`](#fn-from-uri) | Convert a `file://` URI to a local absolute path. | + +### Normalization @@ -67,17 +106,20 @@ Normalize path case using the active path semantics. **Return**: -- `value` (`string`): Path after case normalization. +- `normalizedPath` (`string`): Path after case normalization. **Example**: ```lua -path.normcase("/A/B") --> "/A/B" +path.normcase("ABC") --> "abc" +path.normcase("/A/B") --> "\\a\\b" ``` > [!NOTE] > -> On POSIX semantics this returns the input unchanged. +> On POSIX semantics this returns the input unchanged. Use +> [`mods.ntpath`](/modules/ntpath) to force Windows-style case folding and +> separator normalization. @@ -92,13 +134,13 @@ Join path components. **Return**: -- `value` (`string`): Joined path. +- `joinedPath` (`string`): Joined path. **Example**: ```lua path.join("/usr", "bin") --> "/usr/bin" -path.join([[C:\a]], [[b]]) --> [[C:\a\b]] +path.join([[C:/a]], [[b]]) --> [[C:/a\b]] ``` > [!NOTE] @@ -117,7 +159,7 @@ Normalize separators and dot segments. **Return**: -- `value` (`string`): Normalized path. +- `normalizedPath` (`string`): Normalized path. **Example**: @@ -138,7 +180,7 @@ Return `true` when `path` is absolute. **Return**: -- `value` (`boolean`): True when `path` is absolute. +- `isAbsolute` (`boolean`): True when `path` is absolute. **Example**: @@ -146,7 +188,7 @@ Return `true` when `path` is absolute. path.isabs("/a/b") --> true ``` -### Path Decomposition +### Decomposition @@ -250,7 +292,7 @@ Return final path component. **Return**: -- `value` (`string`): Final path component. +- `basename` (`string`): Final path component. **Example**: @@ -271,7 +313,7 @@ Return directory portion of a path. **Return**: -- `value` (`string`): Parent directory path. +- `dirname` (`string`): Parent directory path. **Example**: @@ -280,7 +322,7 @@ path.dirname("/a/b.txt") --> "/a" path.dirname([[C:\a\b.txt]]) --> [[C:\a]] ``` -### Environment Expand +### Environment @@ -294,7 +336,8 @@ Expand `~` home segment when available. **Return**: -- `value` (`string?`): Path with the home segment expanded when available. +- `expandedPath` (`string?`): Path with the home segment expanded when + available. - `err` (`string?`): Error message when `~` expansion cannot be resolved. **Example**: @@ -304,6 +347,29 @@ path.expanduser("~/tmp") --> "/tmp" (when HOME is set) path.expanduser([[x\y]]) --> [[x\y]] ``` + + +#### `expandvars(path)` + +Expand vars in a path (`$VAR`/`${VAR}` everywhere, `%VAR%` on Windows). + +**Parameters**: + +- `path` (`string`): Path containing variable placeholders. + +**Return**: + +- `expandedPath` (`string`): Path with variable values substituted. + +**Example**: + +```lua +path.expandvars("$HOME/bin") --> "/home/me/bin" +path.expandvars("${XDG_CONFIG_HOME}/nvim") --> "/home/me/.config/nvim" +path.expandvars("%USERPROFILE%\\bin") --> "C:\\Users\\me\\bin" +path.expandvars("$UNKNOWN/bin") --> "$UNKNOWN/bin" +``` + #### `home()` @@ -312,7 +378,7 @@ Return the current user's home directory path. **Return**: -- `value` (`string?`): Home directory path when available. +- `homePath` (`string?`): Home directory path when available. - `err` (`string?`): Error message when the home directory cannot be resolved. **Example**: @@ -321,7 +387,24 @@ Return the current user's home directory path. path.home() ``` -### Derived Paths + + +#### `cwd()` + +Return the current working directory path. + +**Return**: + +- `cwd` (`string?`): Current working directory path. +- `err` (`string?`): Error message when the cwd cannot be resolved. + +**Example**: + +```lua +path.cwd() +``` + +### Derived @@ -335,7 +418,7 @@ Return normalized absolute path. **Return**: -- `value` (`string`): Absolute normalized path. +- `absolutePath` (`string`): Absolute normalized path. **Example**: @@ -357,7 +440,8 @@ Return `path` relative to optional `start` path. **Return**: -- `value` (`string`): Relative path from `start` to `path`. +- `relativePath` (`string?`): Relative path from `start` to `path`. +- `err` (`string?`): Error message when the path cannot be made relative. **Example**: @@ -378,7 +462,8 @@ Return longest common sub-path from a path list. **Return**: -- `value` (`string`): Longest common sub-path. +- `commonPath` (`string?`): Longest common sub-path. +- `err` (`string?`): Error message when inputs are incompatible. **Example**: @@ -387,7 +472,396 @@ path.commonpath({ "/a/b/c", "/a/b/d" }) --> "/a/b" path.commonpath({ [[C:\a\b\c]], [[c:/a/b/d]] }) --> [[C:\a\b]] ``` -> [!NOTE] -> -> All inputs must use compatible drive/root semantics. Mixing absolute and -> relative paths may raise an error. + + +#### `commonprefix(paths)` + +Return longest common leading string prefix. + +**Parameters**: + +- `paths` (`string[]`): List of paths. + +**Return**: + +- `commonPrefix` (`string`): Longest common string prefix. + +**Example**: + +```lua +path.commonprefix({"abc", "abd"}) --> "ab" +path.commonprefix({"/home/swen/spam", "/home/swen/eggs"}) --> "/home/swen/" +path.commonprefix({"abc", "xyz"}) --> "" +``` + +### Anchors + + + +#### `drive(path)` + +Return drive prefix when present. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `drivePrefix` (`string`): Drive prefix. + +**Example**: + +```lua +path.drive("c:a/b") --> "c:" +path.drive("a/b") --> "" +``` + + + +#### `root(path)` + +Return root separator segment when present. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `rootSeparator` (`string`): Root separator segment. + +**Example**: + +```lua +path.root("/tmp/a.txt") --> "/" +path.root("c:/") --> "\\" +path.root("a/b") --> "" +``` + + + +#### `anchor(path)` + +Return drive and root combined. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `anchor` (`string`): Drive and root anchor. + +**Example**: + +```lua +path.anchor("c:\\") --> "c:\\" +``` + +### Components + + + +#### `parts(path)` + +Split path into logical parts, including anchor when present. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `paths` (`mods.List`): Path parts including anchor when present. + +**Example**: + +```lua +path.parts("a/b.txt") --> {"a", "b.txt"} +path.parts("/a/b") --> {"/", "a", "b"} +path.parts("c:a\\b") --> {"c:", "a", "b"} +``` + + + +#### `stem(path)` + +Return filename without its final suffix. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `stem` (`string`): Filename stem. + +**Example**: + +```lua +path.stem("archive.tar.gz") --> "archive.tar" +path.stem("c:a/b") --> "b" +``` + + + +#### `suffixes(path)` + +Return all filename suffixes in order. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `suffixes` (`mods.List`): Filename suffixes. + +**Example**: + +```lua +path.suffixes("archive.tar.gz") --> {".tar", ".gz"} +path.suffixes("a/b") --> {} +``` + + + +#### `parents(path)` + +Return logical parent paths from nearest to farthest. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `parents` (`mods.List`): Ancestor paths from nearest to farthest. + +**Example**: + +```lua +path.parents("a/b/c") --> {"a/b", "a", "."} +path.parents("c:a/b") --> {"c:a", "c:"} +``` + +### Relations + + + +#### `relative_to(path, other, walk_up?)` + +Return `path` relative to `other`, or `nil` with an error when it is not under +`other`. + +When `walk_up` is `true`, allow `..` segments to walk up to a shared prefix. + +**Parameters**: + +- `path` (`string`): Input path. +- `other` (`string`): Reference path. +- `walk_up?` (`boolean`): Allow walking up to a shared prefix. + +**Return**: + +- `relativePath` (`string?`): Path relative to `other`, or `nil` on error. +- `err` (`string?`): Error message when the path cannot be made relative. + +**Example**: + +```lua +path.relative_to("/a/b/c.txt", "/a") --> "b/c.txt" +path.relative_to("/a/b", "/a/c", true) --> "../b" +path.relative_to("/a/b", "/a/x") --> nil, "'/a/b' is not in the subpath of '/a/x'" +``` + + + +#### `is_relative_to(path, other)` + +Return `true` when `path` is under `other`. + +**Parameters**: + +- `path` (`string`): Input path. +- `other` (`string`): Reference path. + +**Return**: + +- `isRelative` (`boolean`): True when `path` is under `other`. + +**Example**: + +```lua +path.is_relative_to("a/b/c", "a/b") --> true +path.is_relative_to("C:A/B", "c:a") --> true +path.is_relative_to("a/b", "a/b/c") --> false +``` + + + +#### `with_name(path, name)` + +Return a path with the final filename replaced. + +**Parameters**: + +- `path` (`string`): Input path. +- `name` (`string`): Replacement filename. + +**Return**: + +- `updatedPath` (`string?`): Path with replaced filename, or `nil` on error. +- `err` (`string?`): Error message when replacement fails. + +**Example**: + +```lua +path.with_name("a/b", "c.txt") --> "a/c.txt" +path.with_name("a/b.txt", "c.lua") --> "a/c.lua" +path.with_name("a/b", "c/d") --> nil, "invalid name 'c/d'" +path.with_name("/", "d.xml") --> nil, "'/' has an empty name" +``` + + + +#### `with_stem(path, stem)` + +Return a path with the final filename stem replaced. + +**Parameters**: + +- `path` (`string`): Input path. +- `stem` (`string`): Replacement filename stem. + +**Return**: + +- `updatedPath` (`string?`): Path with replaced filename stem, or `nil` on + error. +- `err` (`string?`): Error message when replacement fails. + +**Example**: + +```lua +path.with_stem("a/b", "d") --> "/a/d" +path.with_stem("a/b.lua", "d") --> "/a/d.lua" +path.with_stem("/", "d") --> "'/' has an empty name" +path.with_stem("a/b", "d") --> "invalid name ''." +``` + + + +#### `with_suffix(path, suffix)` + +Return a path with the final filename suffix replaced. + +**Parameters**: + +- `path` (`string`): Input path. +- `suffix` (`string`): Replacement suffix. + +**Return**: + +- `updatedPath` (`string?`): Path with replaced suffix, or `nil` on error. +- `err` (`string?`): Error message when replacement fails. + +**Example**: + +```lua +path.with_suffix("a/b", ".gz") --> "a/b/.gz" +path.with_suffix("a/b.gz", ".lua") --> "a/b/.lua" +path.with_suffix("a/b", "gz") --> nil, "invalid suffix 'gz'" +path.with_suffix("//a/b", "gz") --> nil, "'//a/b' has an empty name" +``` + +### Conversions + + + +#### `as_posix(path)` + +Convert backslashes (`\`) to forward slashes (`/`). + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `posixPath` (`string`): POSIX-style path. + +**Example**: + +```lua +path.as_posix("a\\b\\c") --> "a/b/c" +``` + + + +#### `as_uri(path)` + +Convert a local path to a `file://` URI. + +**Parameters**: + +- `path` (`string`): Input path. + +**Return**: + +- `fileUri` (`string?`): File URI. +- `err` (`string?`): Error message when conversion fails. + +**Example**: + +```lua +path.as_uri("/home/user/report.txt") --> "file:///home/user/report.txt" +path.as_uri("c:/a/b.c") --> "file:///c:/a/b.c" +path.as_uri("/a/b%#c") --> "file:///a/b%25%23c" +``` + + + +#### `match(path, pattern, case_sensitive?)` + +Match a path against a glob-style pattern using only `*` and `?` wildcards. + +**Parameters**: + +- `path` (`string`): Input path. +- `pattern` (`string`): Pattern to match. +- `case_sensitive?` (`boolean`): Override platform-default case matching. + +**Return**: + +- `matchesPattern` (`boolean`): True when the path matches. + +**Example**: + +```lua +path.match("a/b.lua", "*.lua") --> true +path.match("A.lua", "a.LUA", false) --> true +path.match("notes.txt", "n?tes.*") --> true +path.match("a/b/c.lua", "a/*/c.lua") --> true +``` + + + +#### `from_uri(uri)` + +Convert a `file://` URI to a local absolute path. + +**Parameters**: + +- `uri` (`string`): URI value. + +**Return**: + +- `path` (`string?`): Resolved absolute path. +- `err` (`string?`): Error message when conversion fails. + +**Example**: + +```lua +path.from_uri("file://localhost/tmp/a.txt") --> "/tmp/a.txt" +``` diff --git a/docs/src/modules/posixpath.md b/docs/src/modules/posixpath.md index c0db09c..48e81d1 100644 --- a/docs/src/modules/posixpath.md +++ b/docs/src/modules/posixpath.md @@ -1,10 +1,10 @@ --- -description: "Path operations for POSIX-style paths." +description: "POSIX-style path operations." --- # `posixpath` -Path operations for POSIX-style paths. +POSIX-style path operations. > 💡 Python `posixpath`-style behavior, ported to Lua. diff --git a/docs/src/modules/repr.md b/docs/src/modules/repr.md index e0ffceb..640edc9 100644 --- a/docs/src/modules/repr.md +++ b/docs/src/modules/repr.md @@ -1,10 +1,10 @@ --- -description: "Render any Lua value as a readable string." +description: "Readable string rendering for Lua values." --- # `repr` -Render any Lua value as a readable string. +Readable string rendering for Lua values. ## Usage diff --git a/docs/src/modules/runtime.md b/docs/src/modules/runtime.md index e8c2b99..6c3e236 100644 --- a/docs/src/modules/runtime.md +++ b/docs/src/modules/runtime.md @@ -1,10 +1,10 @@ --- -description: "Exposes Lua runtime metadata and version compatibility flags." +description: "Lua runtime metadata and version compatibility flags." --- # `runtime` -Exposes Lua runtime metadata and version compatibility flags. +Lua runtime metadata and version compatibility flags. ## Usage diff --git a/docs/src/modules/set.md b/docs/src/modules/set.md index ee20a2b..cad87fb 100644 --- a/docs/src/modules/set.md +++ b/docs/src/modules/set.md @@ -1,13 +1,10 @@ --- -description: - "A set class providing common operations to create, modify, and query - collections of unique values." +description: "A set class for creating, combining, and querying unique values." --- # `Set` -A set class providing common operations to create, modify, and query collections -of unique values. +A set class for creating, combining, and querying unique values. ## Usage @@ -34,24 +31,24 @@ print(s:contains("a")) --> true **Copying**: -| Function | Description | -| ------------------------------------------------------- | --------------------------------------------------- | -| [`copy()`](#fn-copy) | Return a shallow copy of the set. | -| [`difference(set)`](#fn-difference) | Return elements in this set but not in another. | -| [`intersection(set)`](#fn-intersection) | Return elements common to both sets. | -| [`remove(v)`](#fn-remove) | Remove an element if present, do nothing otherwise. | -| [`symmetric_difference(set)`](#fn-symmetric-difference) | Return elements not shared by both sets. | -| [`union(set)`](#fn-union) | Return a new set with all elements from both. | +| Function | Description | +| ----------------------------------------------------- | --------------------------------------------------- | +| [`copy()`](#fn-copy) | Return a shallow copy of the set. | +| [`difference(t)`](#fn-difference) | Return elements in this set but not in another. | +| [`intersection(t)`](#fn-intersection) | Return elements common to both sets. | +| [`remove(v)`](#fn-remove) | Remove an element if present, do nothing otherwise. | +| [`symmetric_difference(t)`](#fn-symmetric-difference) | Return elements not shared by both sets. | +| [`union(t)`](#fn-union) | Return a new set with all elements from both. | **Predicates**: | Function | Description | | ----------------------------------- | ---------------------------------------------------------------- | | [`isdisjoint(set)`](#fn-isdisjoint) | Return true if sets have no elements in common. | -| [`equals(set)`](#fn-equals) | Return true when both sets contain exactly the same members. | +| [`equals(t)`](#fn-equals) | Return true when both sets contain exactly the same members. | | [`isempty()`](#fn-isempty) | Return true if the set has no elements. | -| [`issubset(set)`](#fn-issubset) | Return true if all elements of this set are also in another set. | -| [`issuperset(set)`](#fn-issuperset) | Return true if this set contains all elements of another set. | +| [`issubset(t)`](#fn-issubset) | Return true if all elements of this set are also in another set. | +| [`issuperset(t)`](#fn-issuperset) | Return true if this set contains all elements of another set. | **Query**: @@ -62,23 +59,26 @@ print(s:contains("a")) --> true **Transform**: -| Function | Description | -| ------------------------ | --------------------------------------- | -| [`map(fn)`](#fn-map) | Return a new set by mapping each value. | -| [`values()`](#fn-values) | Return a list of all values in the set. | +| Function | Description | +| --------------------------------- | --------------------------------------- | +| [`map(fn)`](#fn-map) | Return a new set by mapping each value. | +| [`values()`](#fn-values) | Return a list of all values in the set. | +| [`tostring()`](#fn-tostring) | Render the set as a string. | +| [`join(sep?, quoted?)`](#fn-join) | Join set values into a string. | **Metamethods**: -| Function | Description | -| ------------------------- | -------------------------------------------------------------------------- | -| [`__add(set)`](#fn-add) | Return the union of two sets using `+`. | -| [`__bor(set)`](#fn-bor) | Return the union of two sets using `\|`. | -| [`__band(set)`](#fn-band) | Return the intersection of two sets using `&`. | -| [`__bxor(set)`](#fn-bxor) | Return elements present in exactly one set using `^`. | -| [`__eq(set)`](#fn-eq) | Return true if both sets contain exactly the same members using `==`. | -| [`__le(set)`](#fn-le) | Return true if the left set is a subset of the right set using `<=`. | -| [`__lt(set)`](#fn-lt) | Return true if the left set is a proper subset of the right set using `<`. | -| [`__sub(set)`](#fn-sub) | Return the difference of two sets using `-`. | +| Function | Description | +| ------------------------------ | -------------------------------------------------------------------------- | +| [`__add(t)`](#fn-add) | Return the union of two sets using `+`. | +| [`__bor(t)`](#fn-bor) | Return the union of two sets using `\|`. | +| [`__band(t)`](#fn-band) | Return the intersection of two sets using `&`. | +| [`__bxor(t)`](#fn-bxor) | Return elements present in exactly one set using `^`. | +| [`__eq(t)`](#fn-eq) | Return true if both sets contain exactly the same members using `==`. | +| [`__le(t)`](#fn-le) | Return true if the left set is a subset of the right set using `<=`. | +| [`__lt(set)`](#fn-lt) | Return true if the left set is a proper subset of the right set using `<`. | +| [`__sub(set)`](#fn-sub) | Return the difference of two sets using `-`. | +| [`__tostring()`](#fn-tostring) | Render the set via `tostring(set)`. | ### Mutation @@ -94,7 +94,7 @@ Add an element to the set. **Return**: -- `self` (`T`): Current set instance. +- `self` (`T`): Current set. **Example**: @@ -110,7 +110,7 @@ Remove all elements from the set. **Return**: -- `self` (`T`): Current set instance. +- `self` (`T`): Current set. **Example**: @@ -126,11 +126,11 @@ Remove elements found in another set (in place). **Parameters**: -- `set` (`T`): Other set value. +- `set` (`T|mods.List`): Other set/list. **Return**: -- `self` (`T`): Current set instance. +- `self` (`T`): Current set. **Example**: @@ -146,11 +146,11 @@ Keep only elements common to both sets (in place). **Parameters**: -- `set` (`T`): Other set value. +- `set` (`T|mods.List`): Other set/list. **Return**: -- `self` (`T`): Current set instance. +- `self` (`T`): Current set. **Example**: @@ -183,11 +183,11 @@ Update the set with elements not shared by both (in place). **Parameters**: -- `set` (`T`): Other set value. +- `set` (`T|mods.List`): Other set/list. **Return**: -- `self` (`T`): Current set instance. +- `self` (`T`): Current set. **Example**: @@ -204,11 +204,11 @@ Add all elements from another set (in place). **Parameters**: -- `set` (`T`): Other set value. +- `set` (`T|mods.List`): Other set/list. **Return**: -- `self` (`T`): Current set instance. +- `self` (`T`): Current set. **Example**: @@ -236,13 +236,13 @@ c = Set({ "a" }):copy() --> c is a new set with "a" -#### `difference(set)` +#### `difference(t)` Return elements in this set but not in another. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -261,13 +261,13 @@ d = Set({ "a", "b" }):difference(Set({ "b" })) --> d contains "a" -#### `intersection(set)` +#### `intersection(t)` Return elements common to both sets. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -295,7 +295,7 @@ Remove an element if present, do nothing otherwise. **Return**: -- `self` (`T`): Current set instance. +- `self` (`T`): Current set. **Example**: @@ -305,13 +305,13 @@ s = Set({ "a", "b" }):remove("b") --> s contains "a" -#### `symmetric_difference(set)` +#### `symmetric_difference(t)` Return elements not shared by both sets. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -330,13 +330,13 @@ d = Set({ "a", "b" }):symmetric_difference(Set({ "b", "c" })) -#### `union(set)` +#### `union(t)` Return a new set with all elements from both. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -363,7 +363,7 @@ Return true if sets have no elements in common. **Parameters**: -- `set` (`T`): Other set value. +- `set` (`T|mods.List`): Other set/list. **Return**: @@ -377,13 +377,13 @@ ok = Set({ "a" }):isdisjoint(Set({ "b" })) --> true -#### `equals(set)` +#### `equals(t)` Return true when both sets contain exactly the same members. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -420,13 +420,13 @@ empty = Set({}):isempty() --> true -#### `issubset(set)` +#### `issubset(t)` Return true if all elements of this set are also in another set. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -445,13 +445,13 @@ ok = Set({ "a" }):issubset(Set({ "a", "b" })) --> true -#### `issuperset(set)` +#### `issuperset(t)` Return true if this set contains all elements of another set. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -540,17 +540,59 @@ Return a list of all values in the set. values = Set({ "a", "b" }):values() --> { "a", "b" } ``` + + +#### `tostring()` + +Render the set as a string. + +**Return**: + +- `renderedSet` (`string`): Rendered set string. + +**Example**: + +```lua +s = Set({ "b", "a", 1 }):tostring() --> '{ 1, "a", "b" }' +``` + + + +#### `join(sep?, quoted?)` + +Join set values into a string. + +**Parameters**: + +- `sep?` (`string`): Optional separator value (defaults to `""`). +- `quoted?` (`boolean`): Optional boolean flag (defaults to `false`). + +**Return**: + +- `joined` (`string`): Joined string. + +**Example**: + +```lua +s = Set({ "b", "a" }):join(", ") --> "a, b" +s = Set({ "b", "a" }):join(", ", true) --> '"a", "b"' +``` + +> [!NOTE] +> +> Join order is not guaranteed. + ### Metamethods -#### `__add(set)` +#### `__add(t)` Return the union of two sets using `+`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -570,13 +612,13 @@ u = a + b --> { a = true, b = true, c = true } -#### `__bor(set)` +#### `__bor(t)` Return the union of two sets using `|`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -596,13 +638,13 @@ u = a | b --> { a = true, b = true, c = true } -#### `__band(set)` +#### `__band(t)` Return the intersection of two sets using `&`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -622,13 +664,13 @@ i = a & b --> { b = true } -#### `__bxor(set)` +#### `__bxor(t)` Return elements present in exactly one set using `^`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -648,13 +690,13 @@ d = a ^ b --> { a = true, c = true } -#### `__eq(set)` +#### `__eq(t)` Return true if both sets contain exactly the same members using `==`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -672,13 +714,13 @@ ok = Set({ "a", "b" }) == Set({ "b", "a" }) --> true -#### `__le(set)` +#### `__le(t)` Return true if the left set is a subset of the right set using `<=`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `t` (`mods.Set|mods.List|table`): Other set/list. **Return**: @@ -704,7 +746,7 @@ Return true if the left set is a proper subset of the right set using `<`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `set` (`mods.Set|table`): Other set. **Return**: @@ -726,7 +768,7 @@ Return the difference of two sets using `-`. **Parameters**: -- `set` (`mods.Set|table`): Other set value. +- `set` (`mods.Set|table`): Other set. **Return**: @@ -743,3 +785,19 @@ d = a - b --> { a = true } > [!NOTE] > > `__sub` is the operator form of `:difference(set)`. + + + +#### `__tostring()` + +Render the set via `tostring(set)`. + +**Return**: + +- `renderedSet` (`string`): Rendered set string. + +**Example**: + +```lua +s = tostring(Set({ "b", "a", 1 })) --> '{ 1, "a", "b" }' +``` diff --git a/docs/src/modules/str.md b/docs/src/modules/str.md index f449cb1..fa3074c 100644 --- a/docs/src/modules/str.md +++ b/docs/src/modules/str.md @@ -1,10 +1,11 @@ --- -description: "String utility helpers modeled after Python's `str`." +description: + "String operations for searching, splitting, trimming, and formatting text." --- # `str` -String utility helpers modeled after Python's `str`. +String operations for searching, splitting, trimming, and formatting text. ## Usage diff --git a/docs/src/modules/stringcase.md b/docs/src/modules/stringcase.md index a0a2036..68aa650 100644 --- a/docs/src/modules/stringcase.md +++ b/docs/src/modules/stringcase.md @@ -1,10 +1,10 @@ --- -description: "String case conversion helpers." +description: "String case conversion and word splitting." --- # `stringcase` -String case conversion helpers. +String case conversion and word splitting. ## Usage diff --git a/docs/src/modules/tbl.md b/docs/src/modules/tbl.md index f089a1d..432fc0a 100644 --- a/docs/src/modules/tbl.md +++ b/docs/src/modules/tbl.md @@ -1,10 +1,11 @@ --- -description: "Utility functions for working with Lua tables." +description: + "Table operations for querying, copying, merging, and transforming tables." --- # `tbl` -Utility functions for working with Lua tables. +Table operations for querying, copying, merging, and transforming tables. ## Usage @@ -52,6 +53,13 @@ print(tbl.count({ a = 1, b = 2 })) --> 2 | [`update(t1, t2)`](#fn-update) | Merge entries from `t2` into `t1` and return `t1`. | | [`values(t)`](#fn-values) | Return a list of all values in the table. | +**Iteration**: + +| Function | Description | +| ------------------------------- | -------------------------------------------- | +| [`foreach(t, fn)`](#fn-foreach) | Call a function for each value in the table. | +| [`spairs(t)`](#fn-spairs) | Iterate key-value pairs in sorted key order. | + ### Basics Core table utilities for clearing and counting. @@ -153,8 +161,8 @@ Filter entries by a value predicate. **Parameters**: -- `t` (`table`): Input table. -- `pred` (`fun(v:any):boolean`): Value predicate. +- `t` (`table`): Input table. +- `pred` (`fun(value:V):boolean`): Value predicate. **Return**: @@ -176,12 +184,12 @@ Find the first key whose value equals the given value. **Parameters**: -- `t` (`{[T1]:T2}`): Input table. -- `v` (`T2`): Value to find. +- `t` (`table`): Input table. +- `v` (`V`): Value to find. **Return**: -- `key` (`T1?`): First matching key, or `nil` when not found. +- `key` (`K?`): First matching key, or `nil` when not found. **Example**: @@ -220,12 +228,12 @@ Find first value and key matching predicate. **Parameters**: - `t` (`table`): Input table. -- `pred` (`fun(v:T1,k:T2):boolean`): Predicate function. +- `pred` (`fun(key:K,value:V):boolean`): Predicate function. **Return**: -- `matchedValue` (`T1?`): First matching value, or `nil` when not found. -- `k` (`T2?`): Key for the first matching value, or `nil` when not found. +- `value` (`V?`): First matching value, or `nil` when not found. +- `key` (`K?`): Key for the first matching value, or `nil` when not found. **Example**: @@ -272,11 +280,11 @@ Invert keys/values into new table. **Parameters**: -- `t` (`{[T1]:T2}`): Input table. +- `t` (`table`): Input table. **Return**: -- `inverted` (`{[T2]:T1}`): Inverted table (`value -> key`). +- `inverted` (`table`): Inverted table (`value -> key`). **Example**: @@ -312,11 +320,11 @@ Return a list of all keys in the table. **Parameters**: -- `t` (`{[T]:any}`): Input table. +- `t` (`table`): Input table. **Return**: -- `keys` (`mods.List`): List of keys in `t`. +- `keys` (`mods.List`): List of keys in `t`. **Example**: @@ -332,12 +340,12 @@ Return a new table by mapping each value (keys preserved). **Parameters**: -- `t` (`{[T1]:T2}`): Input table. -- `fn` (`fun(v:T2):T3`): Mapping function. +- `t` (`table`): Input table. +- `fn` (`fun(value:V):T`): Mapping function. **Return**: -- `mapped` (`{[T1]:T3}`): New table with mapped values. +- `mapped` (`table`): New table with mapped values. **Example**: @@ -355,12 +363,12 @@ Return a new table by mapping each key-value pair. **Parameters**: -- `t` (`{[T1]:T2}`): Input table. -- `fn` (`fun(k:T1,`): v:T2):T3 Key-value mapping function. +- `t` (`table`): Input table. +- `fn` (`fun(key:K,`): value:V):T Key-value mapping function. **Return**: -- `mapped` (`{[T1]:T3}`): New table with mapped values. +- `mapped` (`table`): New table with mapped values. **Example**: @@ -387,7 +395,7 @@ Merge entries from `t2` into `t1` and return `t1`. **Return**: -- `t1` (`T`): Updated `t1` table. +- `table` (`T`): Updated `t1` table. **Example**: @@ -404,14 +412,63 @@ Return a list of all values in the table. **Parameters**: -- `t` (`{[any]:T}`): Input table. +- `t` (`table`): Input table. **Return**: -- `values` (`mods.List`): List of values in `t`. +- `values` (`mods.List`): List of values in `t`. **Example**: ```lua vals = values({ a = 1, b = 2 }) --> { 1, 2 } ``` + +### Iteration + +Iterators and ordered traversal helpers. + +#### `foreach(t, fn)` + +Call a function for each value in the table. + +**Parameters**: + +- `t` (`table`): Input table. +- `fn` (`fun(value:V,`): key:K) Function invoked for each entry. + +**Return**: + +- `none` (`nil`) + +**Example**: + +```lua +foreach({ a = 1, b = 2 }, function(v, k) + print(k, v) +end) +``` + + + +#### `spairs(t)` + +Iterate key-value pairs in sorted key order. + +**Parameters**: + +- `t` (`T`): Input table. + +**Return**: + +- `table, index?: K):(K, V) iterator Sorted pairs + iterator. +- **value** (`T`) + +**Example**: + +```lua +for k, v in spairs({ b = 2, a = 1 }) do + print(k, v) +end +``` diff --git a/docs/src/modules/template.md b/docs/src/modules/template.md index 6488c2d..292521d 100644 --- a/docs/src/modules/template.md +++ b/docs/src/modules/template.md @@ -1,10 +1,10 @@ --- -description: "Interpolate string placeholders of the form {{." +description: "String template rendering with {{." --- # `template` -Interpolate string placeholders of the form {{...}}. +String template rendering with {{...}} placeholders. ## Usage diff --git a/docs/src/modules/utils.md b/docs/src/modules/utils.md index d3a40a8..e7fa93e 100644 --- a/docs/src/modules/utils.md +++ b/docs/src/modules/utils.md @@ -1,10 +1,10 @@ --- -description: "Small shared utility helpers used by modules in this library." +description: "Shared utility helpers used across the Mods library." --- # `utils` -Small shared utility helpers used by modules in this library. +Shared utility helpers used across the Mods library. ## Usage @@ -16,6 +16,16 @@ print(utils.quote('hello "world"')) --> 'hello "world"' ## Functions +| Function | Description | +| -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | +| [`quote(v)`](#fn-quote) | Smart-quote a string for readable Lua-like output. | +| [`keypath(...)`](#fn-keypath) | Format a key chain as a Lua-like table access path. | +| [`args_repr(v)`](#fn-args-repr) | Format a list-like table as a comma-separated argument string. | +| [`assert_arg(argn, v, validator?, optional?, msg?)`](#fn-assert-arg) | Assert argument value using [`mods.validate`](/modules/validate) and raise a Lua error on failure. | +| [`validate(name, v, validator?, optional?, msg?)`](#fn-validate) | Validate a value using [`mods.validate`](/modules/validate) and raise a Lua error on failure. | +| [`validate(path, v, validator?, optional?, msg?)`](#fn-validate) | Validate a value using [`mods.validate`](/modules/validate) and raise a Lua error on failure. | +| [`lazy_module(name, err?)`](#fn-lazy-module) | Return a lazy proxy for a module. | + ### `quote(v)` @@ -60,9 +70,33 @@ p3 = utils.keypath("ctx", "invalid-key") --> 'ctx["invalid-key"]' p4 = utils.keypath() --> "" ``` + + +### `args_repr(v)` + +Format a list-like table as a comma-separated argument string. + +**Parameters**: + +- `v` (`table|any`): Value to format. + +**Return**: + +- `out` (`string`): Argument list string. + +**Example**: + +```lua +utils.args_repr({ "a", 1, true }) --> '"a", 1, true' +``` + +> [!NOTE] +> +> Requires [`inspect`](https://github.com/kikito/inspect.lua) + -### `assert_arg(argn, v, tp?, level?, msg?)` +### `assert_arg(argn, v, validator?, optional?, msg?)` Assert argument value using [`mods.validate`](/modules/validate) and raise a Lua error on failure. @@ -71,22 +105,23 @@ error on failure. - `argn` (`integer`): Argument index for error context. - `v` (`T`): Value to check. -- `tp?` (`modsIsType`): Validator name (defaults to `"truthy"`). -- `level?` (`integer`): Optional error level for `error(...)` (defaults to `2`). +- `validator?` (`modsValidatorName`): Validator name (defaults to `"truthy"`). +- `optional?` (`boolean`): Skip errors when `v` is `nil` (defaults to `false`). - `msg?` (`string`): Optional override template passed to [`mods.validate`](/modules/validate). **Return**: -- `validatedValue` (`T`): Same input value on success. +- `validatedValue` (`T`): Same input value on success, or `nil` when optional. **Example**: ```lua utils.assert_arg(1, "ok", "string") --> "ok" +utils.assert_arg(2, nil, "string", true) --> nil utils.assert_arg(2, 123, "string") --> raises: bad argument #2 (expected string, got number) -utils.assert_arg(3, "x", "number", 2, "need {{expected}}, got {{got}}") +utils.assert_arg(3, "x", "number", false, "need {{expected}}, got {{got}}") --> raises: bad argument #3 (need number, got string) ``` @@ -94,3 +129,97 @@ utils.assert_arg(3, "x", "number", 2, "need {{expected}}, got {{got}}") > > When the caller function name is available, error text includes > `to ''` (Lua-style bad argument context). + + + +### `validate(name, v, validator?, optional?, msg?)` + +Validate a value using [`mods.validate`](/modules/validate) and raise a Lua +error on failure. + +**Parameters**: + +- `name` (`string`): Name for the error prefix. +- `v` (`any`): Value to validate. +- `validator?` (`modsValidatorName`): Validator name (defaults to `"truthy"`). +- `optional?` (`boolean`): Skip errors when `v` is `nil` (defaults to `false`). +- `msg?` (`string`): Optional override template passed to + [`mods.validate`](/modules/validate). + +**Return**: + +- `none` (`nil`) + +**Example**: + +```lua +utils.validate("path", "ok", "string") +utils.validate("name", nil, "string", true) +utils.validate("count", "x", "number") +--> raises: count: expected number, got string +``` + + + +### `validate(path, v, validator?, optional?, msg?)` + +Validate a value using [`mods.validate`](/modules/validate) and raise a Lua +error on failure. + +**Parameters**: + +- `path` (`table`): Path parts for the error name. +- `v` (`any`): Value to validate. +- `validator?` (`modsValidatorName`): Validator name (defaults to `"truthy"`). +- `optional?` (`boolean`): Skip errors when `v` is `nil` (defaults to `false`). +- `msg?` (`string`): Optional override template passed to + [`mods.validate`](/modules/validate). + +**Return**: + +- `none` (`nil`) + +**Example**: + +```lua +utils.validate({ "ctx", "users", 1, "name" }, nil, "string", true) +utils.validate({ "ctx", "users", 1, "name" }, 123, "string") +--> raises: ctx.users[1].name: expected string, got number +``` + +> [!NOTE] +> +> On failure, `path` is rendered with +> [`mods.utils.keypath`](/modules/utils#fn-keypath). + + + +### `lazy_module(name, err?)` + +Return a lazy proxy for a module. + +The proxy rewrites its metamethods after first access while keeping the proxy +table itself free of cached fields. + +**Parameters**: + +- `name` (`string`): Module name passed to `require`. +- `err?` (`string`): Optional error message raised when loading fails. + +**Return**: + +- `module` (`{}`): Lazy proxy for the loaded module. + +**Example**: + +```lua +local fs = utils.lazy_module("mods.fs") +print(fs.exists("README.md")) + +local repr = utils.lazy_module("mods.repr") +print(repr({ a = 1 })) +``` + +> [!NOTE] +> +> Supports both table-returning modules and function-returning modules. diff --git a/docs/src/modules/validate.md b/docs/src/modules/validate.md index 4605e2d..f904c2d 100644 --- a/docs/src/modules/validate.md +++ b/docs/src/modules/validate.md @@ -1,29 +1,29 @@ --- -description: "Validation checks for values and filesystem path types." +description: "Validation helpers for Lua values and filesystem path types." --- # `validate` -Validation checks for values and filesystem path types. +Validation helpers for Lua values and filesystem path types. ## Usage ```lua local validate = require "mods.validate" -ok, err = validate.number("nope") --> false, "expected number, got string" +ok, err = validate.number("nope") --> false, "number expected, got string" ok, err = validate(123, "number") --> true, nil ``` ## `validate()` -`validate(v, tp)` dispatches to the registered validator `tp`. If `tp` is -omitted, it defaults to `"truthy"`. +`validate(v, validator)` dispatches to the registered validator. If `validator` +is omitted, it defaults to `"truthy"`. ```lua -validate() --> false, "expected truthy value, got no value" +validate() --> false, "truthy value expected, got no value" validate(1) --> true, nil -validate(1, "nil") --> false, "expected nil, got number" +validate(1, "nil") --> false, "nil expected, got number" ``` ## Validator Names @@ -35,63 +35,77 @@ validate.number(1) --> true, nil validate.NumBer(1) --> true, nil ``` -`tp` in `validate(v, tp)` is matched as-is (case-sensitive): +`validator` in `validate(v, validator)` is matched as-is (case-sensitive): ```lua validate(1, "number") --> true, nil -validate(1, "NuMbEr") --> false, "expected NuMbEr, got number" +validate(1, "NuMbEr") --> false, "NuMbEr expected, got number" +``` + +## Custom Messages + +Validator functions accept an optional template override as the second argument: +validate.number(v, "need {{expected}}, got {{got}}")`. + +You can also set `validate.messages.` to define default templates per +validator. + +```lua +validate.string(123, "want {{expected}}, got {{got}}") +--> false, "want string, got number" ``` ## Functions **Type Checks**: -| Function | Description | -| ----------------------------- | -------------------------------------------------------------------------------------------- | -| [`boolean(v)`](#fn-boolean) | Returns `true` when `v` is a boolean. Otherwise returns `false` and an error message. | -| [`function(v)`](#fn-function) | Returns `true` when `v` is a function. Otherwise returns `false` and an error message. | -| [`nil(v)`](#fn-nil) | Returns `true` when `v` is `nil`. Otherwise returns `false` and an error message. | -| [`number(v)`](#fn-number) | Returns `true` when `v` is a number. Otherwise returns `false` and an error message. | -| [`string(v)`](#fn-string) | Returns `true` when `v` is a string. Otherwise returns `false` and an error message. | -| [`table(v)`](#fn-table) | Returns `true` when `v` is a table. Otherwise returns `false` and an error message. | -| [`thread(v)`](#fn-thread) | Returns `true` when `v` is a thread. Otherwise returns `false` and an error message. | -| [`userdata(v)`](#fn-userdata) | Returns `true` when `v` is a userdata value. Otherwise returns `false` and an error message. | +| Function | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------- | +| [`boolean(v, msg?)`](#fn-boolean) | Returns `true` when `v` is a boolean. Otherwise returns `false` and an error message. | +| [`function(v, msg?)`](#fn-function) | Returns `true` when `v` is a function. Otherwise returns `false` and an error message. | +| [`nil(v, msg?)`](#fn-nil) | Returns `true` when `v` is `nil`. Otherwise returns `false` and an error message. | +| [`number(v, msg?)`](#fn-number) | Returns `true` when `v` is a number. Otherwise returns `false` and an error message. | +| [`string(v, msg?)`](#fn-string) | Returns `true` when `v` is a string. Otherwise returns `false` and an error message. | +| [`table(v, msg?)`](#fn-table) | Returns `true` when `v` is a table. Otherwise returns `false` and an error message. | +| [`thread(v, msg?)`](#fn-thread) | Returns `true` when `v` is a thread. Otherwise returns `false` and an error message. | +| [`userdata(v, msg?)`](#fn-userdata) | Returns `true` when `v` is a userdata value. Otherwise returns `false` and an error message. | **Value Checks**: -| Function | Description | -| ----------------------------- | ------------------------------------------------------------------------------------------- | -| [`false(v)`](#fn-false) | Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an error message. | -| [`true(v)`](#fn-true) | Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an error message. | -| [`falsy(v)`](#fn-falsy) | Returns `true` when `v` is falsy. Otherwise returns `false` and an error message. | -| [`callable(v)`](#fn-callable) | Returns `true` when `v` is callable. Otherwise returns `false` and an error message. | -| [`integer(v)`](#fn-integer) | Returns `true` when `v` is an integer. Otherwise returns `false` and an error message. | -| [`truthy(v)`](#fn-truthy) | Returns `true` when `v` is truthy. Otherwise returns `false` and an error message. | +| Function | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------- | +| [`false(v, msg?)`](#fn-false) | Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an error message. | +| [`true(v, msg?)`](#fn-true) | Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an error message. | +| [`falsy(v, msg?)`](#fn-falsy) | Returns `true` when `v` is falsy. Otherwise returns `false` and an error message. | +| [`callable(v, msg?)`](#fn-callable) | Returns `true` when `v` is callable. Otherwise returns `false` and an error message. | +| [`integer(v, msg?)`](#fn-integer) | Returns `true` when `v` is an integer. Otherwise returns `false` and an error message. | +| [`truthy(v, msg?)`](#fn-truthy) | Returns `true` when `v` is truthy. Otherwise returns `false` and an error message. | **Path Checks**: -| Function | Description | -| ------------------------- | ------------------------------------------------------------------------------------------------------- | -| [`block(v)`](#fn-block) | Returns `true` when `v` is a block device path. Otherwise returns `false` and an error message. | -| [`char(v)`](#fn-char) | Returns `true` when `v` is a char device path. Otherwise returns `false` and an error message. | -| [`device(v)`](#fn-device) | Returns `true` when `v` is a block or char device path. Otherwise returns `false` and an error message. | -| [`dir(v)`](#fn-dir) | Returns `true` when `v` is a directory path. Otherwise returns `false` and an error message. | -| [`fifo(v)`](#fn-fifo) | Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error message. | -| [`file(v)`](#fn-file) | Returns `true` when `v` is a file path. Otherwise returns `false` and an error message. | -| [`link(v)`](#fn-link) | Returns `true` when `v` is a symlink path. Otherwise returns `false` and an error message. | -| [`socket(v)`](#fn-socket) | Returns `true` when `v` is a socket path. Otherwise returns `false` and an error message. | +| Function | Description | +| ------------------------------- | ------------------------------------------------------------------------------------------------------- | +| [`path(v, msg?)`](#fn-path) | Returns `true` when `v` is a valid filesystem path. Otherwise returns `false` and an error message. | +| [`block(v, msg?)`](#fn-block) | Returns `true` when `v` is a block device path. Otherwise returns `false` and an error message. | +| [`char(v, msg?)`](#fn-char) | Returns `true` when `v` is a char device path. Otherwise returns `false` and an error message. | +| [`device(v, msg?)`](#fn-device) | Returns `true` when `v` is a block or char device path. Otherwise returns `false` and an error message. | +| [`dir(v, msg?)`](#fn-dir) | Returns `true` when `v` is a directory path. Otherwise returns `false` and an error message. | +| [`fifo(v, msg?)`](#fn-fifo) | Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error message. | +| [`file(v, msg?)`](#fn-file) | Returns `true` when `v` is a file path. Otherwise returns `false` and an error message. | +| [`link(v, msg?)`](#fn-link) | Returns `true` when `v` is a symlink path. Otherwise returns `false` and an error message. | +| [`socket(v, msg?)`](#fn-socket) | Returns `true` when `v` is a socket path. Otherwise returns `false` and an error message. | **Validator API**: -| Function | Description | -| --------------------------------------------- | -------------------------------------------------- | -| [`register(name, check, msg?)`](#fn-register) | Register or override a validator function by name. | +| Function | Description | +| ------------------------------------------------------ | -------------------------------------------------- | +| [`register(name, validator, template?)`](#fn-register) | Register or override a validator function by name. | ### Type Checks Basic Lua type validators (and their negated variants). -#### `boolean(v)` +#### `boolean(v, msg?)` Returns `true` when `v` is a boolean. Otherwise returns `false` and an error message. @@ -99,6 +113,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -109,12 +124,12 @@ message. ```lua ok, err = validate.boolean(true) --> true, nil -ok, err = validate.boolean(1) --> false, "expected boolean, got number" +ok, err = validate.boolean(1) --> false, "boolean expected, got number" ``` -#### `function(v)` +#### `function(v, msg?)` Returns `true` when `v` is a function. Otherwise returns `false` and an error message. @@ -122,6 +137,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -133,12 +149,12 @@ message. ```lua ok, err = validate.Function(function() end) --> true, nil ok, err = validate.Function(1) ---> false, "expected function, got number" +--> false, "function expected, got number" ``` -#### `nil(v)` +#### `nil(v, msg?)` Returns `true` when `v` is `nil`. Otherwise returns `false` and an error message. @@ -146,6 +162,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -156,12 +173,12 @@ message. ```lua ok, err = validate.Nil(nil) --> true, nil -ok, err = validate.Nil(0) --> false, "expected nil, got number" +ok, err = validate.Nil(0) --> false, "nil expected, got number" ``` -#### `number(v)` +#### `number(v, msg?)` Returns `true` when `v` is a number. Otherwise returns `false` and an error message. @@ -169,6 +186,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -179,12 +197,12 @@ message. ```lua ok, err = validate.number(42) --> true, nil -ok, err = validate.number("x") --> false, "expected number, got string" +ok, err = validate.number("x") --> false, "number expected, got string" ``` -#### `string(v)` +#### `string(v, msg?)` Returns `true` when `v` is a string. Otherwise returns `false` and an error message. @@ -192,6 +210,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -202,12 +221,12 @@ message. ```lua ok, err = validate.string("hello") --> true, nil -ok, err = validate.string(1) --> false, "expected string, got number" +ok, err = validate.string(1) --> false, "string expected, got number" ``` -#### `table(v)` +#### `table(v, msg?)` Returns `true` when `v` is a table. Otherwise returns `false` and an error message. @@ -215,6 +234,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -225,12 +245,12 @@ message. ```lua ok, err = validate.table({}) --> true, nil -ok, err = validate.table(1) --> false, "expected table, got number" +ok, err = validate.table(1) --> false, "table expected, got number" ``` -#### `thread(v)` +#### `thread(v, msg?)` Returns `true` when `v` is a thread. Otherwise returns `false` and an error message. @@ -238,6 +258,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -249,12 +270,12 @@ message. ```lua co = coroutine.create(function() end) ok, err = validate.thread(co) --> true, nil -ok, err = validate.thread(1) --> false, "expected thread, got number" +ok, err = validate.thread(1) --> false, "thread expected, got number" ``` -#### `userdata(v)` +#### `userdata(v, msg?)` Returns `true` when `v` is a userdata value. Otherwise returns `false` and an error message. @@ -262,6 +283,7 @@ error message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -272,7 +294,7 @@ error message. ```lua ok, err = validate.userdata(io.stdout) --> true, nil -ok, err = validate.userdata(1) --> false, "expected userdata, got number" +ok, err = validate.userdata(1) --> false, "userdata expected, got number" ``` ### Value Checks @@ -280,7 +302,7 @@ ok, err = validate.userdata(1) --> false, "expected userdata, got number Value-state validators (exact true/false, truthy/falsy, callable, integer). -#### `false(v)` +#### `false(v, msg?)` Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an error message. @@ -288,6 +310,7 @@ error message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -298,12 +321,12 @@ error message. ```lua ok, err = validate.False(false) --> true, nil -ok, err = validate.False(true) --> false, "expected false, got true" +ok, err = validate.False(true) --> false, "false value expected, got true" ``` -#### `true(v)` +#### `true(v, msg?)` Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an error message. @@ -311,6 +334,7 @@ error message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -321,12 +345,12 @@ error message. ```lua ok, err = validate.True(true) --> true, nil -ok, err = validate.True(false) --> false, "expected true, got false" +ok, err = validate.True(false) --> false, "true value expected, got false" ``` -#### `falsy(v)` +#### `falsy(v, msg?)` Returns `true` when `v` is falsy. Otherwise returns `false` and an error message. @@ -334,6 +358,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -344,12 +369,12 @@ message. ```lua ok, err = validate.falsy(false) --> true, nil -ok, err = validate.falsy(1) --> false, "expected falsy, got number" +ok, err = validate.falsy(1) --> false, "falsy value expected, got 1" ``` -#### `callable(v)` +#### `callable(v, msg?)` Returns `true` when `v` is callable. Otherwise returns `false` and an error message. @@ -357,6 +382,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -367,12 +393,12 @@ message. ```lua ok, err = validate.callable(type) --> true, nil -ok, err = validate.callable(1) --> false, "expected callable, got number" +ok, err = validate.callable(1) --> false, "callable value expected, got 1" ``` -#### `integer(v)` +#### `integer(v, msg?)` Returns `true` when `v` is an integer. Otherwise returns `false` and an error message. @@ -380,6 +406,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -390,12 +417,12 @@ message. ```lua ok, err = validate.integer(1) --> true, nil -ok, err = validate.integer(1.5) --> false, "expected integer, got 1.5" +ok, err = validate.integer(1.5) --> false, "integer value expected, got 1.5" ``` -#### `truthy(v)` +#### `truthy(v, msg?)` Returns `true` when `v` is truthy. Otherwise returns `false` and an error message. @@ -403,6 +430,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -413,7 +441,7 @@ message. ```lua ok, err = validate.truthy(1) --> true, nil -ok, err = validate.truthy(false) --> false, "expected truthy, got boolean" +ok, err = validate.truthy(false) --> false, "truthy value expected, got false" ``` ### Path Checks @@ -424,9 +452,32 @@ Filesystem path-kind validators backed by LuaFileSystem (`lfs`). > > Path checks require **LuaFileSystem** > ([`lfs`](https://github.com/lunarmodules/luafilesystem)) and raise an error if -> it is not installed. +> it is not installed. + +#### `path(v, msg?)` + +Returns `true` when `v` is a valid filesystem path. Otherwise returns `false` +and an error message. + +**Parameters**: + +- `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. + +**Return**: -#### `block(v)` +- `isValid` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + +```lua +ok, err = validate.path("README.md") +``` + + + +#### `block(v, msg?)` Returns `true` when `v` is a block device path. Otherwise returns `false` and an error message. @@ -434,6 +485,7 @@ error message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -448,7 +500,7 @@ ok, err = validate.block(".") -#### `char(v)` +#### `char(v, msg?)` Returns `true` when `v` is a char device path. Otherwise returns `false` and an error message. @@ -456,6 +508,7 @@ error message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -470,7 +523,7 @@ ok, err = validate.char(".") -#### `device(v)` +#### `device(v, msg?)` Returns `true` when `v` is a block or char device path. Otherwise returns `false` and an error message. @@ -478,6 +531,7 @@ Returns `true` when `v` is a block or char device path. Otherwise returns **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -492,7 +546,7 @@ ok, err = validate.device(".") -#### `dir(v)` +#### `dir(v, msg?)` Returns `true` when `v` is a directory path. Otherwise returns `false` and an error message. @@ -500,6 +554,7 @@ error message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -514,7 +569,7 @@ ok, err = validate.dir(".") -#### `fifo(v)` +#### `fifo(v, msg?)` Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error message. @@ -522,6 +577,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -536,7 +592,7 @@ ok, err = validate.fifo(".") -#### `file(v)` +#### `file(v, msg?)` Returns `true` when `v` is a file path. Otherwise returns `false` and an error message. @@ -544,6 +600,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -558,7 +615,7 @@ ok, err = validate.file(".") -#### `link(v)` +#### `link(v, msg?)` Returns `true` when `v` is a symlink path. Otherwise returns `false` and an error message. @@ -566,6 +623,7 @@ error message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -580,7 +638,7 @@ ok, err = validate.link(".") -#### `socket(v)` +#### `socket(v, msg?)` Returns `true` when `v` is a socket path. Otherwise returns `false` and an error message. @@ -588,6 +646,7 @@ message. **Parameters**: - `v` (`any`): Value to validate. +- `msg?` (`string`): Optional override template. **Return**: @@ -604,15 +663,15 @@ ok, err = validate.socket(".") -#### `register(name, check, msg?)` +#### `register(name, validator, template?)` Register or override a validator function by name. **Parameters**: - `name` (`string`): Validator name. -- `check` (`fun(v:any):(ok:boolean)`): Validator function. -- `msg?` (`string`): Optional default message template. +- `validator` (`fun(v:any):(ok:boolean)`): Validator function. +- `template?` (`string`): Optional default message template. **Return**: @@ -632,18 +691,22 @@ ok, err = validate(2, "odd") --> false, "2 does not satisfy odd" > [!NOTE] > -> - If `msg` is provided, it becomes the default message template for that +> - If `template` is provided, it becomes the default message template for that > validator. -> - If `msg` is omitted, failures use: `expected {{expected}}, got {{got}}`. +> - If `template` is omitted, failures use: +> `{{expected}} expected, got {{got}}`. ## Fields ### `messages` -Custom error-message templates for validator failures. Set -`validate.messages.`, where `` is a validator name (for example: -`number`, `truthy`, `file`). The template is used only when validation fails and -an error message is returned. +Custom error-message templates for validator failures. + +Set `validate.messages.`, where `` is a validator name (for example: +`number`, `truthy`, `file`). + +The error-message template is used only when validation fails and an error +message is returned. ```lua validate.messages.number = "need {{expected}}, got {{got}}" @@ -664,12 +727,18 @@ ok, err = validate.number("x") --> false, "need number, got string" > When the passed value is `nil`, rendered value text uses `no value`. > > ```lua -> validate.messages.truthy = "expected {{expected}} value, got {{value}}" -> validate.truthy(nil) --> false, "expected truthy value, got no value" +> validate.messages.truthy = "{{expected}} value expected, got {{value}}" +> validate.truthy(nil) --> false, "truthy value expected, got no value" > ``` **Default Messages**: -- Type checks: expected {{expected}}, got {{got}} -- Value checks: expected {{expected}} value, got {{value}} +- Type checks: {{expected}} expected, got {{got}} +- Value checks: {{expected}} value expected, got {{value}} - Path checks: {{value}} is not a valid {{expected}} path + (for `path`: {{value}} is not a valid path) + +> [!NOTE] +> +> For path checks, if the value is not a `string`, the message falls back to +> `messages.string` (as if `validate.string` was called).