From afc3540d4fd75a0af380e8535899441f1874aaa7 Mon Sep 17 00:00:00 2001
From: haithium <128622475+haithium@users.noreply.github.com>
Date: Sun, 22 Feb 2026 22:45:14 +0000
Subject: [PATCH] chore(docs): auto-generate docs
---
docs/src/modules/List.md | 451 +++++++++++++++++++++++++
docs/src/modules/Set.md | 259 +++++++++++++++
docs/src/modules/is.md | 177 +++++-----
docs/src/modules/keyword.md | 88 ++---
docs/src/modules/mods.md | 1 +
docs/src/modules/operator.md | 523 ++++++++---------------------
docs/src/modules/repr.md | 52 +--
docs/src/modules/str.md | 392 ++++++++++++----------
docs/src/modules/stringcase.md | 175 +++++-----
docs/src/modules/tbl.md | 386 ++++++----------------
docs/src/modules/template.md | 148 +++------
docs/src/modules/utils.md | 27 +-
docs/src/modules/validate.md | 580 ++++++++++++++++-----------------
13 files changed, 1723 insertions(+), 1536 deletions(-)
create mode 100644 docs/src/modules/List.md
create mode 100644 docs/src/modules/Set.md
create mode 100644 docs/src/modules/mods.md
diff --git a/docs/src/modules/List.md b/docs/src/modules/List.md
new file mode 100644
index 0000000..0f5c2a6
--- /dev/null
+++ b/docs/src/modules/List.md
@@ -0,0 +1,451 @@
+---
+desc:
+ "A Python-style list class providing common operations to create, modify, and
+ query sequences of values."
+---
+
+# `List`
+
+A Python-style list class providing common operations to create, modify, and
+query sequences of values.
+
+## Usage
+
+```lua
+lsist = require "mods.List"
+
+ls = List({ "a" }):append("b")
+print(ls:contains("b")) --> true
+print(ls:index("b")) --> 2
+```
+
+## Functions
+
+**Predicates**:
+
+| Function | Description |
+| ------------- | ----------------------------------------------- |
+| [`all`](#all) | Return true if all values match the predicate. |
+| [`any`](#any) | Return true if any value matches the predicate. |
+
+**Mutation**:
+
+| Function | Description |
+| --------------------- | -------------------------------------------------------------------- |
+| [`append`](#append) | Append a value to the end of the list. |
+| [`clear`](#clear) | Remove all elements from the list. |
+| [`extend`](#extend) | Extend the list with another list. |
+| [`extract`](#extract) | Extract values matching the predicate and remove them from the list. |
+| [`insert`](#insert) | Insert a value at the given position. |
+| [`insert`](#insert) | Append a value to the end of the list. |
+| [`pop`](#pop) | Remove and return the last element. |
+| [`pop`](#pop) | Remove and return the element at the given position. |
+| [`prepend`](#prepend) | Insert a value at the start of the list. |
+| [`remove`](#remove) | Remove the first matching value. |
+| [`sort`](#sort) | Sort the list in place. |
+
+**Copying**:
+
+| Function | Description |
+| --------------- | ---------------------------------- |
+| [`copy`](#copy) | Return a shallow copy of the list. |
+
+**Query**:
+
+| Function | Description |
+| ----------------------- | ----------------------------------------------------------- |
+| [`contains`](#contains) | Return true if the list contains the value. |
+| [`count`](#count) | Count how many times a value appears. |
+| [`index`](#index) | Return the index of the first matching value. |
+| [`index_if`](#index-if) | Return the index of the first value matching the predicate. |
+| [`len`](#len) | Return the number of elements in the list. |
+
+**Access**:
+
+| Function | Description |
+| ----------------- | ------------------------------------------- |
+| [`first`](#first) | Return the first element or `nil` if empty. |
+| [`last`](#last) | Return the last element or `nil` if empty. |
+
+**Transform**:
+
+| Function | Description |
+| ------------------------------- | ------------------------------------------------------------------------------------------------- |
+| [`difference`](#difference) | Return a new list with values not in the given list. |
+| [`drop`](#drop) | Return a new list without the first n elements. |
+| [`filter`](#filter) | Return a new list with values matching the predicate. |
+| [`flatten`](#flatten) | Flatten one level of nested lists. |
+| [`foreach`](#foreach) | Apply a function to each element (for side effects). Returns nil. |
+| [`group_by`](#group-by) | Group list values by a computed key. |
+| [`intersection`](#intersection) | Return values that are also present in the given list. Order is preserved from the original list. |
+| [`invert`](#invert) | Invert values to indices in a new table. |
+| [`join`](#join) | Join list values into a string. |
+| [`map`](#map) | Return a new list by mapping each value. |
+| [`reduce`](#reduce) | Reduce the list to a single value using an accumulator. |
+| [`reverse`](#reverse) | Return a new list with items reversed. |
+| [`setify`](#setify) | Convert the list to a set. |
+| [`slice`](#slice) | Return a new list containing items from i to j (inclusive). |
+| [`take`](#take) | Return the first n elements as a new list. |
+| [`uniq`](#uniq) | Return a new list with duplicates removed (first occurrence kept). |
+| [`zip`](#zip) | Zip two lists into a list of 2-element tables. |
+
+### Predicates
+
+Boolean checks for list-wide conditions.
+
+#### `all`
+
+Return true if all values match the predicate.
+
+```lua
+is_even = function(v) return v % 2 == 0 end
+ok = List({ 2, 4 }):all(is_even) --> true
+```
+
+> [!NOTE] Empty lists return `true`.
+
+#### `any`
+
+Return true if any value matches the predicate.
+
+```lua
+has_len_2 = function(v) return #v == 2 end
+ok = List({ "a", "bb" }):any(has_len_2) --> true
+```
+
+### Mutation
+
+In-place operations that modify the current list.
+
+#### `append`
+
+Append a value to the end of the list.
+
+```lua
+ls = List({ "a" }):append("b") --> { "a", "b" }
+```
+
+#### `clear`
+
+Remove all elements from the list.
+
+```lua
+ls = List({ "a", "b" }):clear() --> { }
+```
+
+#### `extend`
+
+Extend the list with another list.
+
+```lua
+ls = List({ "a" }):extend({ "b", "c" }) --> { "a", "b", "c" }
+```
+
+#### `extract`
+
+Extract values matching the predicate and remove them from the list.
+
+```lua
+ls = List({ "a", "bb", "c" })
+is_len_1 = function(v) return #v == 1 end
+ex = ls:extract(is_len_1) --> ex = { "a", "c" }, ls = { "bb" }
+```
+
+#### `insert`
+
+Insert a value at the given position.
+
+```lua
+ls = List({ "a", "c" }):insert(2, "b") --> { "a", "b", "c" }
+```
+
+#### `insert`
+
+Append a value to the end of the list.
+
+```lua
+ls = List({ "a", "b" }):insert("b") --> { "a", "b", "c" }
+```
+
+#### `pop`
+
+Remove and return the last element.
+
+```lua
+ls = List({ "a", "b" })
+v = ls:pop() --> v == "b"; ls is { "a" }
+```
+
+#### `pop`
+
+Remove and return the element at the given position.
+
+```lua
+ls = List({ "a", "b", "c" })
+v = ls:pop(2) --> v == "b"; ls is { "a", "c" }
+```
+
+#### `prepend`
+
+Insert a value at the start of the list.
+
+```lua
+ls = List({ "b", "c" })
+ls:prepend("a") --> { "a", "b", "c" }
+```
+
+#### `remove`
+
+Remove the first matching value.
+
+```lua
+ls = List({ "a", "b", "b" })
+ls:remove("b") --> { "a", "b" }
+```
+
+#### `sort`
+
+Sort the list in place.
+
+```lua
+ls = List({ 3, 1, 2 })
+ls:sort() --> { 1, 2, 3 }
+```
+
+### Copying
+
+Operations that return copied list data.
+
+#### `copy`
+
+Return a shallow copy of the list.
+
+```lua
+c = List({ "a", "b" }):copy() --> { "a", "b" }
+```
+
+### Query
+
+Read-only queries for membership, counts, and indices.
+
+#### `contains`
+
+Return true if the list contains the value.
+
+```lua
+ok = List({ "a", "b" }):contains("b") --> true
+```
+
+#### `count`
+
+Count how many times a value appears.
+
+```lua
+n = List({ "a", "b", "b" }):count("b") --> 2
+```
+
+#### `index`
+
+Return the index of the first matching value.
+
+```lua
+i = List({ "a", "b", "c", "b" }):index("b") --> 2
+```
+
+#### `index_if`
+
+Return the index of the first value matching the predicate.
+
+```lua
+gt_1 = function(x) return x > 1 end
+i = List({ 1, 2, 3 }):index_if(gt_1) --> 2
+```
+
+#### `len`
+
+Return the number of elements in the list.
+
+```lua
+n = List({ "a", "b", "c" }):len() --> 3
+```
+
+> [!NOTE] Uses Lua's `#` operator, so length is reliable for contiguous
+> array-like lists.
+
+### Access
+
+Direct element access helpers.
+
+#### `first`
+
+Return the first element or `nil` if empty.
+
+```lua
+v = List({ "a", "b" }):first() --> "a"
+```
+
+#### `last`
+
+Return the last element or `nil` if empty.
+
+```lua
+v = List({ "a", "b" }):last() --> "b"
+```
+
+### Transform
+
+Non-mutating transformations and derived-list operations.
+
+#### `difference`
+
+Return a new list with values not in the given list.
+
+```lua
+d = List({ "a", "b", "c" }):difference({ "b" }) --> { "a", "c" }
+```
+
+#### `drop`
+
+Return a new list without the first n elements.
+
+```lua
+t = List({ "a", "b", "c" }):drop(1) --> { "b", "c" }
+```
+
+#### `filter`
+
+Return a new list with values matching the predicate.
+
+```lua
+is_len_1 = function(v) return #v == 1 end
+f = List({ "a", "bb", "c" }):filter(is_len_1) --> { "a", "c" }
+```
+
+#### `flatten`
+
+Flatten one level of nested lists.
+
+```lua
+f = List({ { "a", "b" }, { "c" } }):flatten() --> { "a", "b", "c" }
+```
+
+#### `foreach`
+
+Apply a function to each element (for side effects). Returns nil.
+
+```lua
+List({ "a", "b" }):foreach(print)
+--> prints -> a
+--> prints -> b
+```
+
+#### `group_by`
+
+Group list values by a computed key.
+
+```lua
+words = { "aa", "b", "ccc", "dd" }
+g = List(words):group_by(string.len) --> { {"b"}, { "aa", "dd" }, { "ccc" } }
+```
+
+#### `intersection`
+
+Return values that are also present in the given list. Order is preserved from
+the original list.
+
+```lua
+i = List({ "a", "b", "a", "c" }):intersection({ "a", "c" })
+--> { "a", "a", "c" }
+```
+
+#### `invert`
+
+Invert values to indices in a new table.
+
+```lua
+t = List({ "a", "b", "c" }):invert() --> { a = 1, b = 2, c = 3 }
+```
+
+#### `join`
+
+Join list values into a string.
+
+```lua
+s = List({ "a", "b", "c" }):join(",") --> "a,b,c"
+```
+
+#### `map`
+
+Return a new list by mapping each value.
+
+```lua
+to_upper = function(v) return v:upper() end
+m = List({ "a", "b" }):map(to_upper) --> { "A", "B" }
+```
+
+#### `reduce`
+
+Reduce the list to a single value using an accumulator.
+
+```lua
+add = function(acc, v) return acc + v end
+sum = List({ 1, 2, 3 }):reduce(add, 0) --> 6
+sum = List({ 1, 2, 3 }):reduce(add, 10) --> 16
+```
+
+> [!NOTE]
+>
+> If init is `nil`, the first element is used as the initial value. Empty lists
+> return init (or `nil` if init is `nil`).
+
+#### `reverse`
+
+Return a new list with items reversed.
+
+```lua
+r = List({ "a", "b", "c" }):reverse() --> { "c", "b", "a" }
+```
+
+#### `setify`
+
+Convert the list to a set.
+
+```lua
+s = List({ "a", "b", "a" }):setify() --> { a = true, b = true }
+```
+
+#### `slice`
+
+Return a new list containing items from i to j (inclusive).
+
+```lua
+t = List({ "a", "b", "c", "d" }):slice(2, 3) --> { "b", "c" }
+```
+
+> [!NOTE] Supports negative indices (-1 is last element).
+
+#### `take`
+
+Return the first n elements as a new list.
+
+```lua
+t = List({ "a", "b", "c" }):take(2) --> { "a", "b" }
+```
+
+#### `uniq`
+
+Return a new list with duplicates removed (first occurrence kept).
+
+```lua
+u = List({ "a", "b", "a", "c" }):uniq() --> { "a", "b", "c" }
+```
+
+#### `zip`
+
+Zip two lists into a list of 2-element tables.
+
+```lua
+z = List({ "a", "b" }):zip({ 1, 2 }) --> { {"a",1}, {"b",2} }
+```
+
+> [!NOTE] Length is the minimum of both lists.
diff --git a/docs/src/modules/Set.md b/docs/src/modules/Set.md
new file mode 100644
index 0000000..d7fc972
--- /dev/null
+++ b/docs/src/modules/Set.md
@@ -0,0 +1,259 @@
+---
+desc:
+ "A Python-style set class providing common operations to create, modify, and
+ query collections of unique values."
+---
+
+# `Set`
+
+A Python-style set class providing common operations to create, modify, and
+query collections of unique values.
+
+## Usage
+
+```lua
+Set = require "mods.Set"
+
+s = Set({ "a" })
+print(s:contains("a")) --> true
+```
+
+## Functions
+
+**Mutation**:
+
+| Function | Description |
+| ------------------------------------------------------------- | ----------------------------------------------------------- |
+| [`add`](#add) | Add an element to the set. |
+| [`clear`](#clear) | Remove all elements from the set. |
+| [`difference_update`](#difference-update) | Remove elements found in another set (in place). |
+| [`discard`](#discard) | Remove an element if present, do nothing otherwise. |
+| [`intersection_update`](#intersection-update) | Keep only elements common to both sets (in place). |
+| [`pop`](#pop) | Remove and return an arbitrary element. |
+| [`symmetric_difference_update`](#symmetric-difference-update) | Update the set with elements not shared by both (in place). |
+| [`update`](#update) | Add all elements from another set (in place). |
+
+**Copying**:
+
+| Function | Description |
+| ----------------------------------------------- | ----------------------------------------------- |
+| [`copy`](#copy) | Return a shallow copy of the set. |
+| [`difference`](#difference) | Return elements in this set but not in another. |
+| [`intersection`](#intersection) | Return elements common to both sets. |
+| [`symmetric_difference`](#symmetric-difference) | Return elements not shared by both sets. |
+| [`union`](#union) | Return a new set with all elements from both. |
+
+**Predicates**:
+
+| Function | Description |
+| --------------------------- | ---------------------------------------------------------------- |
+| [`isdisjoint`](#isdisjoint) | Return true if sets have no elements in common. |
+| [`isempty`](#isempty) | Return true if the set has no elements. |
+| [`issubset`](#issubset) | Return true if all elements of this set are also in another set. |
+| [`issuperset`](#issuperset) | Return true if this set contains all elements of another set. |
+
+**Query**:
+
+| Function | Description |
+| ----------------------- | ----------------------------------------- |
+| [`contains`](#contains) | Return true if the set contains `v`. |
+| [`len`](#len) | Return the number of elements in the set. |
+
+**Transform**:
+
+| Function | Description |
+| ------------------- | --------------------------------------- |
+| [`map`](#map) | Return a new set by mapping each value. |
+| [`values`](#values) | Return a list of all values in the set. |
+
+### Mutation
+
+In-place operations that mutate the current set.
+
+#### `add`
+
+Add an element to the set.
+
+```lua
+s = Set({ "a" }):add("b") --> s contains "a", "b"
+```
+
+#### `clear`
+
+Remove all elements from the set.
+
+```lua
+s = Set({ "a", "b" }):clear() --> s is empty
+```
+
+#### `difference_update`
+
+Remove elements found in another set (in place).
+
+```lua
+s = Set({ "a", "b" }):difference_update(Set({ "b" })) --> s contains "a"
+```
+
+#### `discard`
+
+Remove an element if present, do nothing otherwise.
+
+```lua
+s = Set({ "a", "b" }):discard("b") --> s contains "a"
+```
+
+#### `intersection_update`
+
+Keep only elements common to both sets (in place).
+
+```lua
+s = Set({ "a", "b" }):intersection_update(Set({ "b", "c" }))
+--> s contains "b"
+```
+
+#### `pop`
+
+Remove and return an arbitrary element.
+
+```lua
+v = Set({ "a", "b" }):pop() --> v is either "a" or "b"
+```
+
+#### `symmetric_difference_update`
+
+Update the set with elements not shared by both (in place).
+
+```lua
+s = Set({ "a", "b" }):symmetric_difference_update(Set({ "b", "c" }))
+--> s contains "a", "c"
+```
+
+#### `update`
+
+Add all elements from another set (in place).
+
+```lua
+s = Set({ "a" }):update(Set({ "b" })) --> s contains "a", "b"
+```
+
+### Copying
+
+Non-mutating set operations that return new set instances.
+
+#### `copy`
+
+Return a shallow copy of the set.
+
+```lua
+c = Set({ "a" }):copy() --> c is a new set with "a"
+```
+
+#### `difference`
+
+Return elements in this set but not in another.
+
+```lua
+d = Set({ "a", "b" }):difference(Set({ "b" })) --> d contains "a"
+```
+
+#### `intersection`
+
+Return elements common to both sets.
+
+```lua
+i = Set({ "a", "b" }):intersection(Set({ "b", "c" })) --> i contains "b"
+```
+
+#### `symmetric_difference`
+
+Return elements not shared by both sets.
+
+```lua
+d = Set({ "a", "b" }):symmetric_difference(Set({ "b", "c" }))
+--> d contains "a", "c"
+```
+
+#### `union`
+
+Return a new set with all elements from both.
+
+```lua
+s = Set({ "a" }):union(Set({ "b" })) --> s contains "a", "b"
+```
+
+### Predicates
+
+Boolean checks about set relationships and emptiness.
+
+#### `isdisjoint`
+
+Return true if sets have no elements in common.
+
+```lua
+ok = Set({ "a" }):isdisjoint(Set({ "b" })) --> true
+```
+
+#### `isempty`
+
+Return true if the set has no elements.
+
+```lua
+empty = Set({}):isempty() --> true
+```
+
+#### `issubset`
+
+Return true if all elements of this set are also in another set.
+
+```lua
+ok = Set({ "a" }):issubset(Set({ "a", "b" })) --> true
+```
+
+#### `issuperset`
+
+Return true if this set contains all elements of another set.
+
+```lua
+ok = Set({ "a", "b" }):issuperset(Set({ "a" })) --> true
+```
+
+### Query
+
+Read-only queries for membership and size.
+
+#### `contains`
+
+Return true if the set contains `v`.
+
+```lua
+ok = Set({ "a", "b" }):contains("a") --> true
+ok = Set({ "a", "b" }):contains("z") --> false
+```
+
+#### `len`
+
+Return the number of elements in the set.
+
+```lua
+n = Set({ "a", "b" }):len() --> 2
+```
+
+### Transform
+
+Value-to-value transformations and projection helpers.
+
+#### `map`
+
+Return a new set by mapping each value.
+
+```lua
+s = Set({ 1, 2 }):map(function(v) return v * 10 end) --> s contains 10, 20
+```
+
+#### `values`
+
+Return a list of all values in the set.
+
+```lua
+values = Set({ "a", "b" }):values() --> { "a", "b" }
+```
diff --git a/docs/src/modules/is.md b/docs/src/modules/is.md
index da395f7..2496421 100644
--- a/docs/src/modules/is.md
+++ b/docs/src/modules/is.md
@@ -1,211 +1,212 @@
---
-description:
- Type, truthiness, callable, and filesystem path predicates for Lua values.
+desc: "Type predicates for Lua values and filesystem path kinds."
---
# `is`
-Type predicates for Lua values and filesystem paths.
-
-## Import
-
-```lua
-local mods = require("mods")
-local is = mods.is
-```
+Type predicates for Lua values and filesystem path kinds.
## Usage
```lua
-local ok
+is = require "mods.is"
-ok = is.number(3.14) --> true
+ok = is.number(3.14) --> true
ok = is("hello", "string") --> true
-ok = is.Table({}) --> true
+ok = is.table({}) --> true
```
-> [!NOTE]
+> [!NOTE] Function names exist in both lowercase and capitalized forms, and `is`
+> is also callable as `is(v, tp)`.
>
-> - Function names exist in both lowercase and capitalized forms (for example,
-> `is.table` or `is.Table`).
-> - `is` is callable as `is(v, tp)` where `v` is the value and `tp` is any
-> supported type name.
+> ```lua
+> is.table({}) --> true
+> is.Table({}) --> true
+> is("hello", "string") --> true
+> is("hello", "String") --> true
+> ```
-## Quick Reference
+## Functions
**Type Checks**:
-| Function | Description |
-| ------------------------------ | -------------------------------------- |
-| [`boolean(v)`](#fn-booleanv) | Returns `true` when `v` is a boolean. |
-| [`Function(v)`](#fn-functionv) | Returns `true` when `v` is a function. |
-| [`Nil(v)`](#fn-nilv) | Returns `true` when `v` is `nil`. |
-| [`number(v)`](#fn-numberv) | Returns `true` when `v` is a number. |
-| [`string(v)`](#fn-stringv) | Returns `true` when `v` is a string. |
-| [`table(v)`](#fn-tablev) | Returns `true` when `v` is a table. |
-| [`thread(v)`](#fn-threadv) | Returns `true` when `v` is a thread. |
-| [`userdata(v)`](#fn-userdatav) | Returns `true` when `v` is userdata. |
+| Function | Description |
+| ----------------------- | -------------------------------------- |
+| [`boolean`](#boolean) | Returns `true` when `v` is a boolean. |
+| [`Function`](#function) | Returns `true` when `v` is a function. |
+| [`Nil`](#nil) | Returns `true` when `v` is `nil`. |
+| [`number`](#number) | Returns `true` when `v` is a number. |
+| [`string`](#string) | Returns `true` when `v` is a string. |
+| [`table`](#table) | Returns `true` when `v` is a table. |
+| [`thread`](#thread) | Returns `true` when `v` is a thread. |
+| [`userdata`](#userdata) | Returns `true` when `v` is userdata. |
**Value Checks**:
-| Function | Description |
-| ------------------------------ | ------------------------------------------- |
-| [`False(v)`](#fn-falsev) | Returns `true` when `v` is exactly `false`. |
-| [`True(v)`](#fn-truev) | Returns `true` when `v` is exactly `true`. |
-| [`falsy(v)`](#fn-falsyv) | Returns `true` when `v` is falsy. |
-| [`callable(v)`](#fn-callablev) | Returns `true` when `v` is callable. |
-| [`integer(v)`](#fn-integerv) | Returns `true` when `v` is an integer. |
-| [`truthy(v)`](#fn-truthyv) | Returns `true` when `v` is truthy. |
+| Function | Description |
+| ----------------------- | ------------------------------------------- |
+| [`False`](#false) | Returns `true` when `v` is exactly `false`. |
+| [`True`](#true) | Returns `true` when `v` is exactly `true`. |
+| [`falsy`](#falsy) | Returns `true` when `v` is falsy. |
+| [`callable`](#callable) | Returns `true` when `v` is callable. |
+| [`integer`](#integer) | Returns `true` when `v` is an integer. |
+| [`truthy`](#truthy) | Returns `true` when `v` is truthy. |
**Path Checks**:
-| Function | Description |
-| -------------------------- | ------------------------------------------------------- |
-| [`block(v)`](#fn-blockv) | Returns `true` when `v` is a block device path. |
-| [`char(v)`](#fn-charv) | Returns `true` when `v` is a char device path. |
-| [`device(v)`](#fn-devicev) | Returns `true` when `v` is a block or char device path. |
-| [`dir(v)`](#fn-dirv) | Returns `true` when `v` is a directory path. |
-| [`fifo(v)`](#fn-fifov) | Returns `true` when `v` is a FIFO path. |
-| [`file(v)`](#fn-filev) | Returns `true` when `v` is a file path. |
-| [`link(v)`](#fn-linkv) | Returns `true` when `v` is a symlink path. |
-| [`socket(v)`](#fn-socketv) | Returns `true` when `v` is a socket path. |
-
-## Functions
+| Function | Description |
+| ------------------- | ------------------------------------------------------- |
+| [`block`](#block) | Returns `true` when `v` is a block device path. |
+| [`char`](#char) | Returns `true` when `v` is a char device path. |
+| [`device`](#device) | Returns `true` when `v` is a block or char device path. |
+| [`dir`](#dir) | Returns `true` when `v` is a directory path. |
+| [`fifo`](#fifo) | Returns `true` when `v` is a FIFO path. |
+| [`file`](#file) | Returns `true` when `v` is a file path. |
+| [`link`](#link) | Returns `true` when `v` is a symlink path. |
+| [`socket`](#socket) | Returns `true` when `v` is a socket path. |
### Type Checks
-#### `boolean(v)` {#fn-booleanv}
+Core Lua type checks (`type(v)` family).
+
+#### `boolean`
Returns `true` when `v` is a boolean.
```lua
-is.boolean(true) --> true
+is.boolean(true)
```
-#### `Function(v)` {#fn-functionv}
+#### `Function`
Returns `true` when `v` is a function.
```lua
-is.Function(function() end) --> true
+is.Function(function() end)
```
-#### `Nil(v)` {#fn-nilv}
+#### `Nil`
Returns `true` when `v` is `nil`.
```lua
-is.Nil(nil) --> true
+is.Nil(nil)
```
-#### `number(v)` {#fn-numberv}
+#### `number`
Returns `true` when `v` is a number.
```lua
-is.number(3.14) --> true
+is.number(3.14)
```
-#### `string(v)` {#fn-stringv}
+#### `string`
Returns `true` when `v` is a string.
```lua
-is.string("hello") --> true
+is.string("hello")
```
-#### `table(v)` {#fn-tablev}
+#### `table`
Returns `true` when `v` is a table.
```lua
-is.table({}) --> true
+is.table({})
```
-#### `thread(v)` {#fn-threadv}
+#### `thread`
Returns `true` when `v` is a thread.
```lua
-is.thread(coroutine.create(function() end)) --> true
+is.thread(coroutine.create(function() end))
```
-#### `userdata(v)` {#fn-userdatav}
+#### `userdata`
Returns `true` when `v` is userdata.
```lua
-is.userdata(io.stdout) --> true
+is.userdata(io.stdout)
```
### Value Checks
-#### `False(v)` {#fn-falsev}
+Truthiness, exact-value, and callable checks.
+
+#### `False`
Returns `true` when `v` is exactly `false`.
```lua
-is.False(false) --> true
+is.False(false)
```
-#### `True(v)` {#fn-truev}
+#### `True`
Returns `true` when `v` is exactly `true`.
```lua
-is.True(true) --> true
+is.True(true)
```
-#### `falsy(v)` {#fn-falsyv}
+#### `falsy`
Returns `true` when `v` is falsy.
```lua
-is.falsy(false) --> true
+is.falsy(false)
```
-#### `callable(v)` {#fn-callablev}
+#### `callable`
Returns `true` when `v` is callable.
```lua
-is.callable(function() end) --> true
+is.callable(function() end)
```
-#### `integer(v)` {#fn-integerv}
+#### `integer`
Returns `true` when `v` is an integer.
```lua
-is.integer(42) --> true
+is.integer(42)
```
-#### `truthy(v)` {#fn-truthyv}
+#### `truthy`
Returns `true` when `v` is truthy.
```lua
-is.truthy("non-empty") --> true
+is.truthy("non-empty")
```
### Path Checks
+Filesystem path kind checks.
+
> [!IMPORTANT]
>
> Path checks require **LuaFileSystem**
-> ([`lfs`](https://github.com/lunarmodules/luafilesystem)).
->
-> These functions raise an error if `lfs` is not installed.
+> ([`lfs`](https://github.com/lunarmodules/luafilesystem)) and raise an error it
+> is not installed.
-#### `block(v)` {#fn-blockv}
+#### `block`
Returns `true` when `v` is a block device path.
+Raises an error if [`lfs`](https://github.com/lunarmodules/luafilesystem) is not
+installed.
+
```lua
is.block("/dev/sda")
```
-#### `char(v)` {#fn-charv}
+#### `char`
Returns `true` when `v` is a char device path.
@@ -213,7 +214,7 @@ Returns `true` when `v` is a char device path.
is.char("/dev/null")
```
-#### `device(v)` {#fn-devicev}
+#### `device`
Returns `true` when `v` is a block or char device path.
@@ -221,7 +222,7 @@ Returns `true` when `v` is a block or char device path.
is.device("/dev/null")
```
-#### `dir(v)` {#fn-dirv}
+#### `dir`
Returns `true` when `v` is a directory path.
@@ -229,7 +230,7 @@ Returns `true` when `v` is a directory path.
is.dir("/tmp")
```
-#### `fifo(v)` {#fn-fifov}
+#### `fifo`
Returns `true` when `v` is a FIFO path.
@@ -237,7 +238,7 @@ Returns `true` when `v` is a FIFO path.
is.fifo("/path/to/fifo")
```
-#### `file(v)` {#fn-filev}
+#### `file`
Returns `true` when `v` is a file path.
@@ -245,7 +246,7 @@ Returns `true` when `v` is a file path.
is.file("README.md")
```
-#### `link(v)` {#fn-linkv}
+#### `link`
Returns `true` when `v` is a symlink path.
@@ -253,7 +254,7 @@ Returns `true` when `v` is a symlink path.
is.link("/path/to/link")
```
-#### `socket(v)` {#fn-socketv}
+#### `socket`
Returns `true` when `v` is a socket path.
diff --git a/docs/src/modules/keyword.md b/docs/src/modules/keyword.md
index f25e937..ec35aff 100644
--- a/docs/src/modules/keyword.md
+++ b/docs/src/modules/keyword.md
@@ -1,92 +1,70 @@
---
-description: Lua keyword helpers for reserved-word checks.
+desc: "Lua keyword helpers."
---
-# `keyword`
+# `keyword`
Lua keyword helpers.
-## Import
+## Usage
```lua
-local kw = require("mods.keyword")
-```
-
-## Dependencies
-
-- [`mods.List`] is used by `kwlist()`.
-- [`mods.Set`] is used by `kwset()`.
+kw = require "mods.keyword"
-> [!NOTE]
->
-> These dependencies are lazy-loaded internally 💤, so requiring `mods.keyword`
-> does not immediately load them.
-
-## Quick Reference
-
-| Function | Description |
-| ------------------------------------------------------ | -------------------------------------------------- |
-| [`iskeyword(s)`](#fn-iskeywords) | Return `true` when `s` is a reserved Lua keyword. |
-| [`isidentifier(s)`](#fn-isidentifiers) | Return `true` for valid non-keyword identifiers. |
-| [`kwlist()`](#fn-kwlist) | Return Lua keywords as a [`mods.List`] of strings. |
-| [`kwset()`](#fn-kwset) | Return Lua keywords as a [`mods.Set`] of strings. |
-| [`normalize_identifier(s)`](#fn-normalize_identifiers) | Normalize input to a safe identifier. |
+kw.iskeyword("local")) --> true
+kw.isidentifier("hello_world") --> true
+```
## Functions
-### `iskeyword(s)` {#fn-iskeywords}
+| Function | Description |
+| ----------------------------------------------- | ---------------------------------------------------------------------------------------------- |
+| [`iskeyword`](#iskeyword) | Return `true` when `s` is a reserved Lua keyword. |
+| [`isidentifier`](#isidentifier) | Return `true` when `s` is a valid non-keyword Lua identifier. |
+| [`kwlist`](#kwlist) | Return Lua keywords as a [`mods.List`](https://luamod.github.io/mods/modules/list) of strings. |
+| [`kwset`](#kwset) | Return Lua keywords as a [`mods.Set`](https://luamod.github.io/mods/modules/set) of strings. |
+| [`normalize_identifier`](#normalize-identifier) | Normalize an input into a safe Lua identifier. |
-Return `true` when `s` is a reserved Lua keyword.
+### `iskeyword`
-> [!NOTE]
->
-> `goto` is treated as a keyword on Lua 5.2+ and not on Lua 5.1/LuaJIT.
+Return `true` when `s` is a reserved Lua keyword.
```lua
-print(kw.iskeyword("function")) --> true
-print(kw.iskeyword("hello")) --> false
+kw.iskeyword("function") --> true
+kw.iskeyword("hello") --> false
```
-### `kwlist()` {#fn-kwlist}
+### `isidentifier`
-Return Lua keywords as a [`mods.List`] of strings.
+Return `true` when `s` is a valid non-keyword Lua identifier.
```lua
-local keywords = kw.kwlist()
-print(keywords[1]) --> "and"
-print(keywords[#keywords]) --> "while"
+kw.isidentifier("hello_world") --> true
+kw.isidentifier("local") --> false
```
-### `kwset()` {#fn-kwset}
+### `kwlist`
-Return Lua keywords as a [`mods.Set`] of strings.
+Return Lua keywords as a
+[`mods.List`](https://luamod.github.io/mods/modules/list) of strings.
```lua
-local keywords = kw.kwset()
-print(keywords["and"]) --> true
-print(keywords["hello"]) --> nil
+kw.kwlist():contains("and") --> true
```
-### `isidentifier(s)` {#fn-isidentifiers}
+### `kwset`
-Return `true` when `s` is a valid non-keyword Lua identifier.
+Return Lua keywords as a [`mods.Set`](https://luamod.github.io/mods/modules/set)
+of strings.
```lua
-print(kw.isidentifier("hello_world")) --> true
-print(kw.isidentifier("local")) --> false
+kw.kwlset():contains("and") --> true
```
-### `normalize_identifier(s)` {#fn-normalize_identifiers}
+### `normalize_identifier`
-Normalize input to a safe Lua identifier.
+Normalize an input into a safe Lua identifier.
```lua
-print(kw.normalize_identifier(" 2 bad-name ")) --> "_2_bad_name"
-print(kw.normalize_identifier("local")) --> "local_"
-print(kw.normalize_identifier("end")) --> "end_"
-print(kw.normalize_identifier(" ")) --> "_"
-print(kw.normalize_identifier(false)) --> "false_"
+kw.normalize_identifier(" 2 bad-name ") --> "_2_bad_name"
```
-
-[`mods.List`]: /modules/list
-[`mods.Set`]: /modules/set
diff --git a/docs/src/modules/mods.md b/docs/src/modules/mods.md
new file mode 100644
index 0000000..b4241df
--- /dev/null
+++ b/docs/src/modules/mods.md
@@ -0,0 +1 @@
+# `mods`
diff --git a/docs/src/modules/operator.md b/docs/src/modules/operator.md
index d7e4d3b..fd10c46 100644
--- a/docs/src/modules/operator.md
+++ b/docs/src/modules/operator.md
@@ -1,513 +1,260 @@
---
-description:
- Operator helpers exposed as functions for arithmetic, comparison, logic, and
- indexing.
+desc: "Operator helpers as functions."
---
# `operator`
Operator helpers as functions.
-## Quick Reference
+## Usage
+
+```lua
+operator = require "mods.operator"
+
+print(operator.add(1, 2)) -->> 3
+```
+
+## Functions
**Arithmetic**:
-| Function | Description |
-| --------------------------- | --------------------------------------------- |
-| [`add(a, b)`](#fn-adda-b) | Returns `a + b`. |
-| [`sub(a, b)`](#fn-suba-b) | Returns `a - b`. |
-| [`mul(a, b)`](#fn-mula-b) | Returns `a * b`. |
-| [`div(a, b)`](#fn-diva-b) | Returns `a / b`. |
-| [`idiv(a, b)`](#fn-idiva-b) | Returns integer division `math.floor(a / b)`. |
-| [`mod(a, b)`](#fn-moda-b) | Returns `a % b`. |
-| [`pow(a, b)`](#fn-powa-b) | Returns `a ^ b`. |
-| [`unm(a)`](#fn-unma) | Returns `-a`. |
+| Function | Description |
+| --------------- | ------------------------------------------------------------------ |
+| [`add`](#add) | Add two numbers. |
+| [`sub`](#sub) | Subtract `b` from `a`. |
+| [`mul`](#mul) | Multiply two numbers. |
+| [`div`](#div) | Divide `a` by `b` using Lua's floating-point division. |
+| [`idiv`](#idiv) | Divide `a` by `b` and return the integer quotient (`//` behavior). |
+| [`mod`](#mod) | Return the modulo remainder of `a` divided by `b`. |
+| [`pow`](#pow) | Raise `a` to the power of `b`. |
+| [`unm`](#unm) | Negate a number. |
**Comparison**:
-| Function | Description |
-| ------------------------- | ----------------- |
-| [`eq(a, b)`](#fn-eqa-b) | Returns `a == b`. |
-| [`neq(a, b)`](#fn-neqa-b) | Returns `a ~= b`. |
-| [`lt(a, b)`](#fn-lta-b) | Returns `a < b`. |
-| [`le(a, b)`](#fn-lea-b) | Returns `a <= b`. |
-| [`gt(a, b)`](#fn-gta-b) | Returns `a > b`. |
-| [`ge(a, b)`](#fn-gea-b) | Returns `a >= b`. |
+| Function | Description |
+| ------------- | -------------------------------------------------- |
+| [`eq`](#eq) | Check whether two values are equal. |
+| [`neq`](#neq) | Check whether two values are not equal. |
+| [`lt`](#lt) | Check whether `a` is strictly less than `b`. |
+| [`le`](#le) | Check whether `a` is less than or equal to `b`. |
+| [`gt`](#gt) | Check whether `a` is strictly greater than `b`. |
+| [`ge`](#ge) | Check whether `a` is greater than or equal to `b`. |
**Logical**:
-| Function | Description |
-| --------------------------- | ------------------ |
-| [`land(a, b)`](#fn-landa-b) | Returns `a and b`. |
-| [`lor(a, b)`](#fn-lora-b) | Returns `a or b`. |
-| [`lnot(a)`](#fn-lnota) | Returns `not a`. |
+| Function | Description |
+| --------------- | ---------------------------------------------------- |
+| [`land`](#land) | Evaluate `a and b` with Lua short-circuit semantics. |
+| [`lor`](#lor) | Evaluate `a or b` with Lua short-circuit semantics. |
+| [`lnot`](#lnot) | Return the boolean negation of `a`. |
**String & Length**:
-| Function | Description |
-| ------------------------------- | ----------------- |
-| [`concat(a, b)`](#fn-concata-b) | Returns `a .. b`. |
-| [`len(a)`](#fn-lena) | Returns `#a`. |
+| Function | Description |
+| ------------------- | ---------------------------------------------------------------- |
+| [`concat`](#concat) | Concatenate two strings. |
+| [`len`](#len) | Return the length of a string or table using Lua's `#` operator. |
**Tables & Calls**:
-| Function | Description |
-| ---------------------------------------- | -------------------------------- |
-| [`index(t, k)`](#fn-indext-k) | Returns `t[k]`. |
-| [`setindex(t, k, v)`](#fn-setindext-k-v) | Sets `t[k] = v` and returns `v`. |
-| [`call(f, ...)`](#fn-callf-varargs) | Calls `f(...)`. |
-
-## Functions
+| Function | Description |
+| ----------------------- | -------------------------------------------------------------- |
+| [`index`](#index) | Return the value at key/index `k` in table `t`. |
+| [`setindex`](#setindex) | Set `t[k] = v` and return the assigned value. |
+| [`call`](#call) | Call a function with variadic arguments and return its result. |
### Arithmetic
-#### `add(a, b)` {#fn-adda-b}
-
-Returns `a + b`.
+Numeric arithmetic operators as functions.
-::: code-group
+#### `add`
-```lua [example.lua]
-add(1, 2) -- 3
-```
+Add two numbers.
-```lua [signature.lua]
----@param a number
----@param b number
----@return number sum
----@nodiscard
-function add(a, b) end
+```lua
+add(1, 2) --> 3
```
-:::
+#### `sub`
-#### `sub(a, b)` {#fn-suba-b}
+Subtract `b` from `a`.
-Returns `a - b`.
-
-::: code-group
-
-```lua [example.lua]
-sub(5, 3) -- 2
+```lua
+sub(5, 3) --> 2
```
-```lua [signature.lua]
----@param a number
----@param b number
----@return number difference
----@nodiscard
-function sub(a, b) end
-```
+#### `mul`
-:::
+Multiply two numbers.
-#### `mul(a, b)` {#fn-mula-b}
-
-Returns `a * b`.
-
-::: code-group
-
-```lua [example.lua]
-mul(3, 4) -- 12
+```lua
+mul(3, 4) --> 12
```
-```lua [signature.lua]
----@param a number
----@param b number
----@return number product
----@nodiscard
-function mul(a, b) end
-```
-
-:::
-
-#### `div(a, b)` {#fn-diva-b}
+#### `div`
-Returns `a / b`.
+Divide `a` by `b` using Lua's floating-point division.
-::: code-group
-
-```lua [example.lua]
-div(10, 4) -- 2.5
-```
-
-```lua [signature.lua]
----@param a number
----@param b number
----@return number quotient
----@nodiscard
-function div(a, b) end
+```lua
+div(10, 4) --> 2.5
```
-:::
-
-#### `idiv(a, b)` {#fn-idiva-b}
-
-Returns integer division `math.floor(a / b)`.
+#### `idiv`
-::: code-group
+Divide `a` by `b` and return the integer quotient (`//` behavior).
-```lua [example.lua]
-idiv(5, 2) -- 2
+```lua
+idiv(5, 2) --> 2
```
-```lua [signature.lua]
----@param a number
----@param b number
----@return integer quotient
----@nodiscard
-function idiv(a, b) end
-```
-
-:::
-
-#### `mod(a, b)` {#fn-moda-b}
+#### `mod`
-Returns `a % b`.
-
-::: code-group
-
-```lua [example.lua]
-mod(5, 2) -- 1
-```
+Return the modulo remainder of `a` divided by `b`.
-```lua [signature.lua]
----@param a number
----@param b number
----@return number remainder
----@nodiscard
-function mod(a, b) end
+```lua
+mod(5, 2) --> 1
```
-:::
+#### `pow`
-#### `pow(a, b)` {#fn-powa-b}
+Raise `a` to the power of `b`.
-Returns `a ^ b`.
-
-::: code-group
-
-```lua [example.lua]
-pow(2, 4) -- 16
+```lua
+pow(2, 4) --> 16
```
-```lua [signature.lua]
----@param a number
----@param b number
----@return number power
----@nodiscard
-function pow(a, b) end
-```
-
-:::
-
-#### `unm(a)` {#fn-unma}
+#### `unm`
-Returns `-a`.
+Negate a number.
-::: code-group
-
-```lua [example.lua]
-unm(3) -- -3
-```
-
-```lua [signature.lua]
----@param a number
----@return number negated
----@nodiscard
-function unm(a) end
+```lua
+unm(3) --> -3
```
-:::
-
### Comparison
-#### `eq(a, b)` {#fn-eqa-b}
-
-Returns `a == b`.
+Equality and ordering comparison operators.
-::: code-group
+#### `eq`
-```lua [example.lua]
-eq(1, 1) -- true
-```
+Check whether two values are equal.
-```lua [signature.lua]
----@param a any
----@param b any
----@return boolean isEqual
----@nodiscard
-function eq(a, b) end
+```lua
+eq(1, 1) --> true
```
-:::
+#### `neq`
-#### `neq(a, b)` {#fn-neqa-b}
+Check whether two values are not equal.
-Returns `a ~= b`.
-
-::: code-group
-
-```lua [example.lua]
-neq(1, 2) -- true
+```lua
+neq(1, 2) --> true
```
-```lua [signature.lua]
----@param a any
----@param b any
----@return boolean isNotEqual
----@nodiscard
-function neq(a, b) end
-```
-
-:::
-
-#### `lt(a, b)` {#fn-lta-b}
+#### `lt`
-Returns `a < b`.
+Check whether `a` is strictly less than `b`.
-::: code-group
-
-```lua [example.lua]
-lt(1, 2) -- true
-```
-
-```lua [signature.lua]
----@param a number
----@param b number
----@return boolean isLess
----@nodiscard
-function lt(a, b) end
+```lua
+lt(1, 2) --> true
```
-:::
-
-#### `le(a, b)` {#fn-lea-b}
-
-Returns `a <= b`.
-
-::: code-group
+#### `le`
-```lua [example.lua]
-lte(2, 2) -- true
-```
+Check whether `a` is less than or equal to `b`.
-```lua [signature.lua]
----@param a number
----@param b number
----@return boolean isLessOrEqual
----@nodiscard
-function le(a, b) end
+```lua
+lte(2, 2) --> true
```
-:::
-
-#### `gt(a, b)` {#fn-gta-b}
-
-Returns `a > b`.
+#### `gt`
-::: code-group
+Check whether `a` is strictly greater than `b`.
-```lua [example.lua]
-gt(3, 2) -- true
+```lua
+gt(3, 2) --> true
```
-```lua [signature.lua]
----@param a number
----@param b number
----@return boolean isGreater
----@nodiscard
-function gt(a, b) end
-```
-
-:::
-
-#### `ge(a, b)` {#fn-gea-b}
+#### `ge`
-Returns `a >= b`.
+Check whether `a` is greater than or equal to `b`.
-::: code-group
-
-```lua [example.lua]
-gte(2, 2) -- true
-```
-
-```lua [signature.lua]
----@param a number
----@param b number
----@return boolean isGreaterOrEqual
----@nodiscard
-function ge(a, b) end
+```lua
+gte(2, 2) --> true
```
-:::
-
### Logical
-#### `land(a, b)` {#fn-landa-b}
-
-Returns `a and b`.
+Boolean logic operators with Lua truthiness semantics.
-::: code-group
+#### `land`
-```lua [example.lua]
-land(true, false) -- false
-```
+Evaluate `a and b` with Lua short-circuit semantics.
-```lua [signature.lua]
----@generic T1,T2
----@param a T1
----@param b T2
----@return T1|T2 andValue
----@nodiscard
-function land(a, b) end
+```lua
+land(true, false) --> false
```
-:::
+#### `lor`
-#### `lor(a, b)` {#fn-lora-b}
+Evaluate `a or b` with Lua short-circuit semantics.
-Returns `a or b`.
-
-::: code-group
-
-```lua [example.lua]
-lor(false, true) -- true
+```lua
+lor(false, true) --> true
```
-```lua [signature.lua]
----@generic T1,T2
----@param a T1
----@param b T2
----@return T1|T2 orValue
----@nodiscard
-function lor(a, b) end
-```
-
-:::
-
-#### `lnot(a)` {#fn-lnota}
+#### `lnot`
-Returns `not a`.
+Return the boolean negation of `a`.
-::: code-group
-
-```lua [example.lua]
-lnot(true) -- false
-```
-
-```lua [signature.lua]
----@param a any
----@return boolean isNot
----@nodiscard
-function lnot(a) end
+```lua
+lnot(true) --> false
```
-:::
-
### String & Length
-#### `concat(a, b)` {#fn-concata-b}
-
-Returns `a .. b`.
+String concatenation and length operators.
-::: code-group
+#### `concat`
-```lua [example.lua]
-concat("a", "b") -- "ab"
-```
+Concatenate two strings.
-```lua [signature.lua]
----@param a string
----@param b string
----@return string concatenated
----@nodiscard
-function concat(a, b) end
+```lua
+concat("a", "b") --> "ab"
```
-:::
+#### `len`
-#### `len(a)` {#fn-lena}
+Return the length of a string or table using Lua's `#` operator.
-Returns `#a`.
-
-::: code-group
-
-```lua [example.lua]
-len("abc") -- 3
+```lua
+len("abc") --> 3
```
-```lua [signature.lua]
----@param a string|table
----@return integer length
----@nodiscard
-function len(a) end
-```
-
-:::
-
### Tables & Calls
-#### `index(t, k)` {#fn-indext-k}
+Table indexing helpers and function invocation.
-Returns `t[k]`.
+#### `index`
-::: code-group
+Return the value at key/index `k` in table `t`.
-```lua [example.lua]
-index({ a = 1 }, "a") -- 1
+```lua
+index({ a = 1 }, "a") --> 1
```
-```lua [signature.lua]
----@generic T
----@param t table
----@param k T
----@return T value
----@nodiscard
-function index(t, k) end
-```
-
-:::
-
-#### `setindex(t, k, v)` {#fn-setindext-k-v}
+#### `setindex`
-Sets `t[k] = v` and returns `v`.
-
-::: code-group
-
-```lua [example.lua]
-setindex({}, "a", 1) -- 1
-```
+Set `t[k] = v` and return the assigned value.
-```lua [signature.lua]
----@generic T
----@param t table
----@param k any
----@param v T
----@return T value
----@nodiscard
-function setindex(t, k, v) end
+```lua
+setindex({}, "a", 1) --> 1
```
-:::
+#### `call`
-#### `call(f, ...)` {#fn-callf-varargs}
+Call a function with variadic arguments and return its result.
-Calls `f(...)`.
-
-::: code-group
-
-```lua [example.lua]
-call(math.max, 1, 2) -- 2
+```lua
+call(math.max, 1, 2) --> 2
```
-
-```lua [signature.lua]
----@generic T,T2
----@param f fun(...:T):T2
----@param ... T
----@return T2 result
----@nodiscard
-function call(f, ...) end
-```
-
-:::
diff --git a/docs/src/modules/repr.md b/docs/src/modules/repr.md
index 309f4b9..3e59146 100644
--- a/docs/src/modules/repr.md
+++ b/docs/src/modules/repr.md
@@ -1,49 +1,27 @@
---
-editLinkTarget: types/repr.lua
-description: Fast, readable string rendering for Lua values and nested tables.
+desc: "Render any Lua value as a readable string."
---
-# `repr`
+# `repr`
Render any Lua value as a readable string.
-## Import
+## Usage
```lua
-local mods = require("mods.repr")
-```
+repr = require "mods.repr"
-## Usage
+print(repr("Hello world!")) --> "Hello world!"
-```lua
-local out = repr({
- user = { name = "Ada", role = "Engineer" },
- count = 3,
- msg = 'He said "hi"',
-})
--- result:
--- {
--- count = 3,
--- msg = 'He said "hi"',
--- user = {
--- name = "Ada",
--- role = "Engineer"
--- }
--- }
+print(repr({ user = { name = "Ada", tags = { "lua", "docs" } } }))
+--> {
+-- user = {
+-- name = "Ada",
+-- tags = {
+-- [1] = "lua",
+-- [2] = "docs"
+-- }
+-- }
+-- }
-out = repr({
- user = {
- name = "Ada",
- meta = { role = "Engineer" },
- },
-})
--- result:
--- {
--- user = {
--- meta = {
--- role = "Engineer"
--- },
--- name = "Ada"
--- }
--- }
```
diff --git a/docs/src/modules/str.md b/docs/src/modules/str.md
index 3675394..69af7be 100644
--- a/docs/src/modules/str.md
+++ b/docs/src/modules/str.md
@@ -1,459 +1,507 @@
---
-description:
- Python-like string utilities for formatting, predicates, splitting, and
- casing.
+desc: "String utility helpers modeled after Python's `str`."
---
# `str`
String utility helpers modeled after Python's `str`.
-## Quick Reference
-
-**Quick Reference: Formatting**:
-
-| Function | Description |
-| --------------------------------------------------------------------- | --------------------------------------------------------------------- |
-| [`capitalize(s)`](#fn-capitalizes) | Return copy with first character capitalized and the rest lowercased. |
-| [`center(s, width, fillchar)`](#fn-centers-width-fillchar) | Center string within width, padded with fill characters. |
-| [`count(s, sub, start, stop)`](#fn-counts-sub-start-stop) | Count non-overlapping occurrences of a substring. |
-| [`endswith(s, suffix, start, stop)`](#fn-endswiths-suffix-start-stop) | Return true if string ends with suffix. |
-| [`expandtabs(s, tabsize)`](#fn-expandtabss-tabsize) | Expand tabs to spaces using given tabsize. |
-| [`find(s, sub, start, stop)`](#fn-finds-sub-start-stop) | Return lowest index of substring or nil if not found. |
-| [`format_map(s, mapping)`](#fn-format_maps-mapping) | Format string with mapping (key-based) replacement. |
-
-**Quick Reference: Predicates**:
-
-| Function | Description |
-| -------------------------------------- | -------------------------------------------------------------------------------------------- |
-| [`isalnum(s)`](#fn-isalnums) | Return true if all characters are alphanumeric and string is non-empty. |
-| [`isalpha(s)`](#fn-isalphas) | Return true if all characters are alphabetic and string is non-empty. |
-| [`isascii(s)`](#fn-isasciis) | Return true if all characters are ASCII and string is non-empty. |
-| [`isdecimal(s)`](#fn-isdecimals) | Return true if all characters are decimal characters and string is non-empty. |
-| [`isdigit(s)`](#fn-isdigits) | Return true if all characters are digits and string is non-empty. |
-| [`isidentifier(s)`](#fn-isidentifiers) | Return true if string is a valid identifier and not a reserved keyword. |
-| [`islower(s)`](#fn-islowers) | Return true if all cased characters are lowercase and there is at least one cased character. |
-| [`isnumeric(s)`](#fn-isnumerics) | Return true if all characters are numeric and string is non-empty. |
-| [`isprintable(s)`](#fn-isprintables) | Return true if all characters are printable and string is non-empty. |
-| [`isspace(s)`](#fn-isspaces) | Return true if all characters are whitespace and string is non-empty. |
-| [`istitle(s)`](#fn-istitles) | Return true if string is titlecased. |
-| [`isupper(s)`](#fn-isuppers) | Return true if all cased characters are uppercase and there is at least one cased character. |
-
-**Quick Reference: Layout**:
-
-| Function | Description |
-| -------------------------------------------------------- | ------------------------------------------------------------- |
-| [`join(sep, ls)`](#fn-joinsep-ls) | Join an iterable of strings using this string as separator. |
-| [`ljust(s, width, fillchar)`](#fn-ljusts-width-fillchar) | Left-justify string in a field of given width. |
-| [`lower(s)`](#fn-lowers) | Return lowercased copy. |
-| [`lstrip(s, chars)`](#fn-lstrips-chars) | Remove leading characters (default: whitespace). |
-| [`rstrip(s, chars)`](#fn-rstrips-chars) | Remove trailing characters (default: whitespace). |
-| [`strip(s, chars)`](#fn-strips-chars) | Remove leading and trailing characters (default: whitespace). |
-
-**Quick Reference: Split & Replace**:
-
-| Function | Description |
-| ----------------------------------------------------------- | ------------------------------------------------------------------------- |
-| [`partition(s, sep)`](#fn-partitions-sep) | Partition string into head, sep, tail from left. |
-| [`removeprefix(s, prefix)`](#fn-removeprefixs-prefix) | Remove prefix if present. |
-| [`removesuffix(s, suffix)`](#fn-removesuffixs-suffix) | Remove suffix if present. |
-| [`replace(s, old, new, count)`](#fn-replaces-old-new-count) | Return a copy of the string with all occurrences of a substring replaced. |
-| [`rfind(s, sub, start, stop)`](#fn-rfinds-sub-start-stop) | Return highest index of substring or nil if not found. |
-| [`rindex(s, sub, start, stop)`](#fn-rindexs-sub-start-stop) | Like rfind but raises on failure (placeholder). |
-| [`rjust(s, width, fillchar)`](#fn-rjusts-width-fillchar) | Right-justify string in a field of given width. |
-| [`rpartition(s, sep)`](#fn-rpartitions-sep) | Partition string into head, sep, tail from right. |
-| [`rsplit(s, sep, maxsplit)`](#fn-rsplits-sep-maxsplit) | Split from the right by separator, up to maxsplit. |
-| [`split(s, sep, maxsplit)`](#fn-splits-sep-maxsplit) | Split by separator (or whitespace) up to maxsplit. |
-| [`splitlines(s, keepends)`](#fn-splitliness-keepends) | Split on line boundaries. |
-
-**Quick Reference: Casing & Transform**:
-
-| Function | Description |
-| ------------------------------------------------------------------------- | --------------------------------------------------------- |
-| [`swapcase(s)`](#fn-swapcases) | Return a copy with case of alphabetic characters swapped. |
-| [`startswith(s, prefix, start, stop)`](#fn-startswiths-prefix-start-stop) | Return true if string starts with prefix. |
-| [`title(s)`](#fn-titles) | Return titlecased copy. |
-| [`translate(s, table_map)`](#fn-translates-table_map) | Translate characters using a mapping table. |
-| [`upper(s)`](#fn-uppers) | Return uppercased copy. |
-| [`zfill(s, width)`](#fn-zfills-width) | Pad numeric string on the left with zeros. |
+## Usage
+
+```lua
+str = require "mods.str"
+
+print(str.capitalize("hello world")) --> "Hello world"
+```
## Functions
+**Formatting**:
+
+| Function | Description |
+| --------------------------- | ----------------------------------------------------------------------------------------------- |
+| [`capitalize`](#capitalize) | Return copy with first character capitalized and the rest lowercased. |
+| [`center`](#center) | Center string within width, padded with fill characters. |
+| [`count`](#count) | Count non-overlapping occurrences of a substring. |
+| [`endswith`](#endswith) | Return true if string ends with suffix. If suffix is a list, return true if any suffix matches. |
+| [`expandtabs`](#expandtabs) | Expand tabs to spaces using given tabsize. |
+| [`find`](#find) | Return lowest index of substring or nil if not found. |
+| [`format_map`](#format-map) | Format string with mapping (key-based) replacement. |
+
+**Predicates**:
+
+| Function | Description |
+| ------------------------------- | -------------------------------------------------------------------------------------------- |
+| [`isalnum`](#isalnum) | Return true if all characters are alphanumeric and string is non-empty. |
+| [`isalpha`](#isalpha) | Return true if all characters are alphabetic and string is non-empty. |
+| [`isascii`](#isascii) | Return true if all characters are ASCII and string is non-empty. |
+| [`isdecimal`](#isdecimal) | Return true if all characters are decimal characters and string is non-empty. |
+| [`isdigit`](#isdigit) | Return true if all characters are digits and string is non-empty. |
+| [`isidentifier`](#isidentifier) | Return true if string is a valid identifier and not a reserved keyword. |
+| [`islower`](#islower) | Return true if all cased characters are lowercase and there is at least one cased character. |
+| [`isnumeric`](#isnumeric) | Return true if all characters are numeric and string is non-empty. |
+| [`isprintable`](#isprintable) | Return true if all characters are printable and string is non-empty. |
+| [`isspace`](#isspace) | Return true if all characters are whitespace and string is non-empty. |
+| [`istitle`](#istitle) | Return true if string is titlecased. |
+| [`isupper`](#isupper) | Return true if all cased characters are uppercase and there is at least one cased character. |
+
+**Layout**:
+
+| Function | Description |
+| ------------------- | ------------------------------------------------------------- |
+| [`join`](#join) | Join an iterable of strings using this string as separator. |
+| [`ljust`](#ljust) | Left-justify string in a field of given width. |
+| [`lower`](#lower) | Return lowercased copy. |
+| [`lstrip`](#lstrip) | Remove leading characters (default: whitespace). |
+| [`rstrip`](#rstrip) | Remove trailing characters (default: whitespace). |
+| [`strip`](#strip) | Remove leading and trailing characters (default: whitespace). |
+
+**Split & Replace**:
+
+| Function | Description |
+| ------------------------------- | ------------------------------------------------------------------------- |
+| [`partition`](#partition) | Partition string into head, sep, tail from left. |
+| [`removeprefix`](#removeprefix) | Remove prefix if present. |
+| [`removesuffix`](#removesuffix) | Remove suffix if present. |
+| [`replace`](#replace) | Return a copy of the string with all occurrences of a substring replaced. |
+| [`rfind`](#rfind) | Return highest index of substring or nil if not found. |
+| [`rindex`](#rindex) | Like rfind but raises on failure (placeholder). |
+| [`rjust`](#rjust) | Right-justify string in a field of given width. |
+| [`rpartition`](#rpartition) | Partition string into head, sep, tail from right. |
+| [`rsplit`](#rsplit) | Split from the right by separator, up to maxsplit. |
+| [`split`](#split) | Split by separator (or whitespace) up to maxsplit. |
+| [`splitlines`](#splitlines) | Split on line boundaries. |
+
+**Casing & Transform**:
+
+| Function | Description |
+| --------------------------- | ------------------------------------------------------------------------------------------------- |
+| [`swapcase`](#swapcase) | Return a copy with case of alphabetic characters swapped. |
+| [`startswith`](#startswith) | Return true if string starts with prefix. If prefix is a list, return true if any prefix matches. |
+| [`title`](#title) | Return titlecased copy. |
+| [`translate`](#translate) | Translate characters using a mapping table. |
+| [`upper`](#upper) | Return uppercased copy. |
+| [`zfill`](#zfill) | Pad numeric string on the left with zeros. |
+
### Formatting
-#### `capitalize(s)` {#fn-capitalizes}
+#### `capitalize`
Return copy with first character capitalized and the rest lowercased.
```lua
-local s = capitalize("hello WORLD") --> "Hello world"
+s = capitalize("hello WORLD")
+--result: "Hello world"
```
-#### `center(s, width, fillchar)` {#fn-centers-width-fillchar}
+#### `center`
Center string within width, padded with fill characters.
```lua
-local s = center("hi", 6, "-") --> "--hi--"
+s = center("hi", 6, "-")
+--result: "--hi--"
```
-#### `count(s, sub, start, stop)` {#fn-counts-sub-start-stop}
+#### `count`
Count non-overlapping occurrences of a substring.
```lua
-local n = count("aaaa", "aa") --> 2
-n = count("aaaa", "a", 2, -1) --> 2
-n = count("abcd", "") --> 5
+n = count("aaaa", "aa")
+--result: 2
+
+n = count("aaaa", "a", 2, -1)
+--result: 2
+
+n = count("abcd", "")
+--result: 5
```
-#### `endswith(s, suffix, start, stop)` {#fn-endswiths-suffix-start-stop}
+#### `endswith`
Return true if string ends with suffix. If suffix is a list, return true if any
suffix matches.
```lua
-local ok = endswith("hello.lua", ".lua") --> true
+ok = endswith("hello.lua", ".lua")
+--result: true
```
-#### `expandtabs(s, tabsize)` {#fn-expandtabss-tabsize}
+#### `expandtabs`
Expand tabs to spaces using given tabsize.
```lua
-local s = expandtabs("a\tb", 4) --> "a b"
+s = expandtabs("a\tb", 4)
+--result: "a b"
```
-#### `find(s, sub, start, stop)` {#fn-finds-sub-start-stop}
+#### `find`
Return lowest index of substring or nil if not found.
```lua
-local i = find("hello", "ll") --> 3
+i = find("hello", "ll")
+--result: 3
```
-#### `format_map(s, mapping)` {#fn-format_maps-mapping}
+#### `format_map`
Format string with mapping (key-based) replacement.
```lua
-local s = format_map("hi {name}", { name = "bob" }) --> "hi bob"
+s = format_map("hi {name}", { name = "bob" })
+--result: "hi bob"
```
### Predicates
-#### `isalnum(s)` {#fn-isalnums}
+#### `isalnum`
Return true if all characters are alphanumeric and string is non-empty.
```lua
-local ok = isalnum("abc123") --> true
+ok = isalnum("abc123")
+--result: true
```
-> [!NOTE]
->
-> Lua letters are ASCII by default, so non-ASCII letters are not alphanumeric.
+> [!NOTE] Lua letters are ASCII by default, so non-ASCII letters are not
+> alphanumeric.
>
> ```lua
> isalnum("á1")` --> `false`
> ```
-#### `isalpha(s)` {#fn-isalphas}
+#### `isalpha`
Return true if all characters are alphabetic and string is non-empty.
```lua
-local ok = isalpha("abc") --> true
+ok = isalpha("abc")
+--result: true
```
-> [!NOTE]
->
-> Lua letters are ASCII by default, so non-ASCII letters are not alphabetic.
+> [!NOTE] Lua letters are ASCII by default, so non-ASCII letters are not
+> alphabetic.
>
> ```lua
> isalpha("á")` --> `false`
> ```
-#### `isascii(s)` {#fn-isasciis}
+#### `isascii`
Return true if all characters are ASCII and string is non-empty.
```lua
-local ok = isascii("hello") --> true
+ok = isascii("hello")
+--result: true
```
-> [!NOTE]
->
-> The empty string returns `true`.
+> [!NOTE] The empty string returns `true`.
-#### `isdecimal(s)` {#fn-isdecimals}
+#### `isdecimal`
Return true if all characters are decimal characters and string is non-empty.
```lua
-local ok = isdecimal("123") --> true
+ok = isdecimal("123")
+--result: true
```
-#### `isdigit(s)` {#fn-isdigits}
+#### `isdigit`
Return true if all characters are digits and string is non-empty.
```lua
-local ok = isdigit("123") --> true
+ok = isdigit("123")
+--result: true
```
-#### `isidentifier(s)` {#fn-isidentifiers}
+#### `isidentifier`
Return true if string is a valid identifier and not a reserved keyword.
```lua
-local ok = isidentifier("foo_bar") --> true
-ok = isidentifier("2var") --> false
-ok = isidentifier("end") --> false (keyword)
+ok = isidentifier("foo_bar")
+--result: true
+
+ok = isidentifier("2var")
+--result: false
+
+ok = isidentifier("end")
+--result: false (keyword)
```
-#### `islower(s)` {#fn-islowers}
+#### `islower`
Return true if all cased characters are lowercase and there is at least one
cased character.
```lua
-local ok = islower("hello") --> true
+ok = islower("hello")
+--result: true
```
-#### `isnumeric(s)` {#fn-isnumerics}
+#### `isnumeric`
Return true if all characters are numeric and string is non-empty.
```lua
-local ok = isnumeric("123") --> true
+ok = isnumeric("123")
+--result: true
```
-#### `isprintable(s)` {#fn-isprintables}
+#### `isprintable`
Return true if all characters are printable and string is non-empty.
```lua
-local ok = isprintable("abc!") --> true
+ok = isprintable("abc!")
+--result: true
```
-> [!NOTE]
->
-> The empty string returns `true`.
+> [!NOTE] The empty string returns `true`.
-#### `isspace(s)` {#fn-isspaces}
+#### `isspace`
Return true if all characters are whitespace and string is non-empty.
```lua
-local ok = isspace(" \t") --> true
+ok = isspace(" \t")
+--result: true
```
-#### `istitle(s)` {#fn-istitles}
+#### `istitle`
Return true if string is titlecased.
```lua
-local ok = istitle("Hello World") --> true
+ok = istitle("Hello World")
+--result: true
```
-#### `isupper(s)` {#fn-isuppers}
+#### `isupper`
Return true if all cased characters are uppercase and there is at least one
cased character.
```lua
-local ok = isupper("HELLO") --> true
+ok = isupper("HELLO")
+--result: true
```
### Layout
-#### `join(sep, ls)` {#fn-joinsep-ls}
+#### `join`
Join an iterable of strings using this string as separator.
```lua
-local s = join(",", { "a", "b", "c" }) --> "a,b,c"
+s = join(",", { "a", "b", "c" })
+--result: "a,b,c"
```
-#### `ljust(s, width, fillchar)` {#fn-ljusts-width-fillchar}
+#### `ljust`
Left-justify string in a field of given width.
```lua
-local s = ljust("hi", 5, ".") --> "hi..."
+s = ljust("hi", 5, ".")
+--result: "hi..."
```
-#### `lower(s)` {#fn-lowers}
+#### `lower`
Return lowercased copy.
```lua
-local s = lower("HeLLo") --> "hello"
+s = lower("HeLLo")
+--result: "hello"
```
-#### `lstrip(s, chars)` {#fn-lstrips-chars}
+#### `lstrip`
Remove leading characters (default: whitespace).
```lua
-local s = lstrip(" hello") --> "hello"
+s = lstrip(" hello")
+--result: "hello"
```
-#### `rstrip(s, chars)` {#fn-rstrips-chars}
+#### `rstrip`
Remove trailing characters (default: whitespace).
```lua
-local s = rstrip("hello ") --> "hello"
+s = rstrip("hello ")
+--result: "hello"
```
-#### `strip(s, chars)` {#fn-strips-chars}
+#### `strip`
Remove leading and trailing characters (default: whitespace).
```lua
-local s = strip(" hello ") --> "hello"
+s = strip(" hello ")
+--result: "hello"
```
### Split & Replace
-#### `partition(s, sep)` {#fn-partitions-sep}
+#### `partition`
Partition string into head, sep, tail from left.
```lua
-local a, b, c = partition("a-b-c", "-") --> "a", "-", "b-c"
+a, b, c = partition("a-b-c", "-")
+--result: "a", "-", "b-c"
```
-#### `removeprefix(s, prefix)` {#fn-removeprefixs-prefix}
+#### `removeprefix`
Remove prefix if present.
```lua
-local s = removeprefix("foobar", "foo") --> "bar"
+s = removeprefix("foobar", "foo")
+--result: "bar"
```
-#### `removesuffix(s, suffix)` {#fn-removesuffixs-suffix}
+#### `removesuffix`
Remove suffix if present.
```lua
-local s = removesuffix("foobar", "bar") --> "foo"
+s = removesuffix("foobar", "bar")
+--result: "foo"
```
-#### `replace(s, old, new, count)` {#fn-replaces-old-new-count}
+#### `replace`
Return a copy of the string with all occurrences of a substring replaced.
```lua
-local s = replace("a-b-c", "-", "_", 1) --> "a_b-c"
+s = replace("a-b-c", "-", "_", 1)
+--result: "a_b-c"
```
-#### `rfind(s, sub, start, stop)` {#fn-rfinds-sub-start-stop}
+#### `rfind`
Return highest index of substring or nil if not found.
```lua
-local i = rfind("ababa", "ba") --> 4
+i = rfind("ababa", "ba")
+--result: 4
```
-#### `rindex(s, sub, start, stop)` {#fn-rindexs-sub-start-stop}
+#### `rindex`
Like rfind but raises on failure (placeholder).
```lua
-local i = rindex("ababa", "ba") --> 4
+i = rindex("ababa", "ba")
+--result: 4
```
-#### `rjust(s, width, fillchar)` {#fn-rjusts-width-fillchar}
+#### `rjust`
Right-justify string in a field of given width.
```lua
-local s = rjust("hi", 5, ".") --> "...hi"
+s = rjust("hi", 5, ".")
+--result: "...hi"
```
-#### `rpartition(s, sep)` {#fn-rpartitions-sep}
+#### `rpartition`
Partition string into head, sep, tail from right.
```lua
-local a, b, c = rpartition("a-b-c", "-") --> "a-b", "-", "c"
+a, b, c = rpartition("a-b-c", "-")
+--result: "a-b", "-", "c"
```
-#### `rsplit(s, sep, maxsplit)` {#fn-rsplits-sep-maxsplit}
+#### `rsplit`
Split from the right by separator, up to maxsplit.
```lua
-local parts = rsplit("a,b,c", ",", 1) --> { "a,b", "c" }
+parts = rsplit("a,b,c", ",", 1)
+--result: { "a,b", "c" }
```
-#### `split(s, sep, maxsplit)` {#fn-splits-sep-maxsplit}
+#### `split`
Split by separator (or whitespace) up to maxsplit.
```lua
-local parts = split("a,b,c", ",") --> { "a", "b", "c" }
+parts = split("a,b,c", ",")
+--result: { "a", "b", "c" }
```
-#### `splitlines(s, keepends)` {#fn-splitliness-keepends}
+#### `splitlines`
Split on line boundaries.
```lua
-local lines = splitlines("a\nb\r\nc") --> { "a", "b", "c" }
+lines = splitlines("a\nb\r\nc")
+--result: { "a", "b", "c" }
```
### Casing & Transform
-#### `swapcase(s)` {#fn-swapcases}
+#### `swapcase`
Return a copy with case of alphabetic characters swapped.
```lua
-local s = swapcase("AbC") --> "aBc"
+s = swapcase("AbC")
+--result: "aBc"
```
-#### `startswith(s, prefix, start, stop)` {#fn-startswiths-prefix-start-stop}
+#### `startswith`
Return true if string starts with prefix. If prefix is a list, return true if
any prefix matches.
```lua
-local ok = startswith("hello.lua", "he") --> true
+ok = startswith("hello.lua", "he")
+--result: true
```
-#### `title(s)` {#fn-titles}
+#### `title`
Return titlecased copy.
```lua
-local s = title("hello world") --> "Hello World"
+s = title("hello world")
+--result: "Hello World"
```
-#### `translate(s, table_map)` {#fn-translates-table_map}
+#### `translate`
Translate characters using a mapping table.
```lua
-local map = { [string.byte("a")] = "b", ["c"] = false }
-local s = translate("abc", map) --> "bb"
+map = { [string.byte("a")] = "b", ["c"] = false }
+s = translate("abc", map)
+--result: "bb"
```
-#### `upper(s)` {#fn-uppers}
+#### `upper`
Return uppercased copy.
```lua
-local s = upper("Hello") --> "HELLO"
+s = upper("Hello")
+--result: "HELLO"
```
-#### `zfill(s, width)` {#fn-zfills-width}
+#### `zfill`
Pad numeric string on the left with zeros.
```lua
-local s = zfill("42", 5) --> "00042"
+s = zfill("42", 5)
+--result: "00042"
```
diff --git a/docs/src/modules/stringcase.md b/docs/src/modules/stringcase.md
index 920890d..aabbfe5 100644
--- a/docs/src/modules/stringcase.md
+++ b/docs/src/modules/stringcase.md
@@ -1,209 +1,198 @@
---
-description:
- Convert strings across naming conventions like snake_case, camelCase, and
- kebab-case.
+desc: "String case conversion helpers."
---
# `stringcase`
String case conversion helpers.
-## Import
-
-```lua
-local sc = require("mods.stringcase")
-```
-
## Usage
```lua
-local s = "FooBar baz"
+sc = require "mods.stringcase"
-sc.snake(s) --> "foo_bar_baz"
-sc.camel(s) --> "fooBarBaz"
-sc.kebab(s) --> "foo-bar-baz"
-sc.title(s) --> "Foo Bar Baz"
+print(stringcase.snake("FooBar")) --> "foo_bar"
```
-## Quick Reference
-
-**Quick Reference: Basic**:
-
-| Function | Description |
-| ------------------------ | -------------------------------- |
-| [`lower(s)`](#fn-lowers) | Convert string to all lowercase. |
-| [`upper(s)`](#fn-uppers) | Convert string to all uppercase. |
-
-**Quick Reference: Word Case**:
-
-| Function | Description |
-| ------------------------------------- | --------------------------------------------------------------------- |
-| [`snake(s)`](#fn-snakes) | Convert string to snake_case. |
-| [`camel(s)`](#fn-camels) | Convert string to camelCase. |
-| [`replace(s, sep)`](#fn-replaces-sep) | Normalize to snake_case, then replace underscores with a separator. |
-| [`acronym(s)`](#fn-acronyms) | Get acronym of words in string (first letters only). |
-| [`title(s)`](#fn-titles) | Convert string to Title Case (first letter of each word capitalized). |
-| [`constant(s)`](#fn-constants) | Convert string to CONSTANT_CASE (uppercase snake_case). |
-| [`pascal(s)`](#fn-pascals) | Convert string to PascalCase. |
-| [`kebab(s)`](#fn-kebabs) | Convert string to kebab-case. |
-| [`dot(s)`](#fn-dots) | Convert string to dot.case. |
-| [`space(s)`](#fn-spaces) | Convert string to space case (spaces between words). |
-| [`path(s)`](#fn-paths) | Convert string to path/case (slashes between words). |
-
-**Quick Reference: Letter Case**:
-
-| Function | Description |
-| ------------------------------ | ------------------------------------------------------------------------- |
-| [`swap(s)`](#fn-swaps) | Swap case of each letter. |
-| [`capital(s)`](#fn-capitals) | Capitalize the first letter and lowercase the rest. |
-| [`sentence(s)`](#fn-sentences) | Convert string to sentence case (first letter uppercase, rest lowercase). |
-
## Functions
+**Basic**:
+
+| Function | Description |
+| ----------------- | -------------------------------- |
+| [`lower`](#lower) | Convert string to all lowercase. |
+| [`upper`](#upper) | Convert string to all uppercase. |
+
+**Word Case**:
+
+| Function | Description |
+| ----------------------- | --------------------------------------------------------------------- |
+| [`snake`](#snake) | Convert string to snake_case. |
+| [`camel`](#camel) | Convert string to camelCase. |
+| [`replace`](#replace) | Normalize to snake_case, then replace underscores with a separator. |
+| [`acronym`](#acronym) | Get acronym of words in string (first letters only). |
+| [`title`](#title) | Convert string to Title Case (first letter of each word capitalized). |
+| [`constant`](#constant) | Convert string to CONSTANT_CASE (uppercase snake_case). |
+| [`pascal`](#pascal) | Convert string to PascalCase. |
+| [`kebab`](#kebab) | Convert string to kebab-case. |
+| [`dot`](#dot) | Convert string to dot.case. |
+| [`space`](#space) | Convert string to space case (spaces between words). |
+| [`path`](#path) | Convert string to path/case (slashes between words). |
+
+**Letter Case**:
+
+| Function | Description |
+| ----------------------- | ------------------------------------------------------------------------- |
+| [`swap`](#swap) | Swap case of each letter. |
+| [`capital`](#capital) | Capitalize the first letter and lowercase the rest. |
+| [`sentence`](#sentence) | Convert string to sentence case (first letter uppercase, rest lowercase). |
+
### Basic
-#### `lower(s)` {#fn-lowers}
+#### `lower`
Convert string to all lowercase.
```lua
-sc.lower("foo_bar-baz") --> "foo_bar-baz"
-sc.lower("FooBar baz") --> "foobar baz"
+lower("foo_bar-baz") --> "foo_bar-baz"
+lower("FooBar baz") --> "foobar baz"
```
-#### `upper(s)` {#fn-uppers}
+#### `upper`
Convert string to all uppercase.
```lua
-sc.upper("foo_bar-baz") --> "FOO_BAR-BAZ"
-sc.upper("FooBar baz") --> "FOOBAR BAZ"
+upper("foo_bar-baz") --> "FOO_BAR-BAZ"
+upper("FooBar baz") --> "FOOBAR BAZ"
```
### Word Case
-#### `snake(s)` {#fn-snakes}
+#### `snake`
Convert string to snake_case.
```lua
-sc.snake("foo_bar-baz") --> "foo_bar_baz"
-sc.snake("FooBar baz") --> "foo_bar_baz"
+snake("foo_bar-baz") --> "foo_bar_baz"
+snake("FooBar baz") --> "foo_bar_baz"
```
-#### `camel(s)` {#fn-camels}
+#### `camel`
Convert string to camelCase.
```lua
-sc.camel("foo_bar-baz") --> "fooBarBaz"
-sc.camel("FooBar baz") --> "fooBarBaz"
+camel("foo_bar-baz") --> "fooBarBaz"
+camel("FooBar baz") --> "fooBarBaz"
```
-#### `replace(s, sep)` {#fn-replaces-sep}
+#### `replace`
Normalize to snake_case, then replace underscores with a separator.
```lua
-sc.replace("foo_bar-baz", "-") --> "foo-bar-baz"
-sc.replace("FooBar baz", "-") --> "foo-bar-baz"
+replace("foo_bar-baz", "-") --> "foo-bar-baz"
+replace("FooBar baz", "-") --> "foo-bar-baz"
```
-#### `acronym(s)` {#fn-acronyms}
+#### `acronym`
Get acronym of words in string (first letters only).
```lua
-sc.acronym("foo_bar-baz") --> "FBB"
+acronym("foo_bar-baz") --> "FBB"
+acronym("FooBar baz") --> "FBB"
```
-#### `title(s)` {#fn-titles}
+#### `title`
Convert string to Title Case (first letter of each word capitalized).
```lua
-sc.title("foo_bar-baz") --> "Foo Bar Baz"
-sc.title("FooBar baz") --> "Foo Bar Baz"
+title("foo_bar-baz") --> "Foo Bar Baz"
+title("FooBar baz") --> "Foo Bar Baz"
```
-#### `constant(s)` {#fn-constants}
+#### `constant`
Convert string to CONSTANT_CASE (uppercase snake_case).
```lua
-sc.constant("foo_bar-baz") --> "FOO_BAR_BAZ"
+constant("foo_bar-baz") --> "FOO_BAR_BAZ"
+constant("FooBar baz") --> "FOO_BAR_BAZ"
```
-#### `pascal(s)` {#fn-pascals}
+#### `pascal`
Convert string to PascalCase.
```lua
-sc.pascal("foo_bar-baz") --> "FooBarBaz"
-sc.pascal("FooBar baz") --> "FooBarBaz"
+pascal("foo_bar-baz") --> "FooBarBaz"
+pascal("FooBar baz") --> "FooBarBaz"
```
-#### `kebab(s)` {#fn-kebabs}
+#### `kebab`
Convert string to kebab-case.
```lua
-sc.kebab("foo_bar-baz") --> "foo-bar-baz"
-sc.kebab("FooBar baz") --> "foo-bar-baz"
+kebab("foo_bar-baz") --> "foo-bar-baz"
+kebab("FooBar baz") --> "foo-bar-baz"
```
-#### `dot(s)` {#fn-dots}
+#### `dot`
Convert string to dot.case.
```lua
-sc.dot("foo_bar-baz") --> "foo.bar.baz"
-sc.dot("FooBar baz") --> "foo.bar.baz"
+dot("foo_bar-baz") --> "foo.bar.baz"
+dot("FooBar baz") --> "foo.bar.baz"
```
-#### `space(s)` {#fn-spaces}
+#### `space`
Convert string to space case (spaces between words).
```lua
-sc.space("foo_bar-baz") --> "foo bar baz"
-sc.space("FooBar baz") --> "foo bar baz"
+space("foo_bar-baz") --> "foo bar baz"
+space("FooBar baz") --> "foo bar baz"
```
-#### `path(s)` {#fn-paths}
+#### `path`
Convert string to path/case (slashes between words).
```lua
-sc.path("foo_bar-baz") --> "foo/bar/baz"
-sc.path("FooBar baz") --> "foo/bar/baz"
+path("foo_bar-baz") --> "foo/bar/baz"
+path("FooBar baz") --> "foo/bar/baz"
```
### Letter Case
-#### `swap(s)` {#fn-swaps}
+#### `swap`
Swap case of each letter.
```lua
-sc.swap("foo_bar-baz") --> "FOO_BAR-BAZ"
-sc.swap("FooBar baz") --> "fOObAR BAZ"
+swap("foo_bar-baz") --> "FOO_BAR-BAZ"
+swap("FooBar baz") --> "fOObAR BAZ"
```
-#### `capital(s)` {#fn-capitals}
+#### `capital`
Capitalize the first letter and lowercase the rest.
```lua
-sc.capital("foo_bar-baz") --> "Foo_bar-baz"
-sc.capital("FooBar baz") --> "Foobar baz"
+capital("foo_bar-baz") --> "Foo_bar-baz"
+capital("FooBar baz") --> "Foobar baz"
```
-#### `sentence(s)` {#fn-sentences}
+#### `sentence`
Convert string to sentence case (first letter uppercase, rest lowercase).
```lua
-sc.sentence("foo_bar-baz") --> "Foo_bar-baz"
-sc.sentence("FooBar baz") --> "FooBar baz"
+sentence("foo_bar-baz") --> "Foo_bar-baz"
+sentence("FooBar baz") --> "FooBar baz"
```
diff --git a/docs/src/modules/tbl.md b/docs/src/modules/tbl.md
index 802dfde..f86ac0e 100644
--- a/docs/src/modules/tbl.md
+++ b/docs/src/modules/tbl.md
@@ -1,392 +1,204 @@
---
-description:
- Lua table helpers for copy, query, transform, and safe nested access patterns.
+desc: "Utility functions for working with Lua tables."
---
# `tbl`
Utility functions for working with Lua tables.
-## Quick Reference
+## Usage
+
+```lua
+tbl = require "mods.tbl"
+
+print(tbl.count({ a = 1, b = 2 })) --> 2
+```
+
+## Functions
**Basics**:
-| Function | Description |
-| ------------------------ | --------------------------------------- |
-| [`clear(t)`](#fn-cleart) | Remove all entries from the table. |
-| [`count(t)`](#fn-countt) | Return the number of keys in the table. |
+| Function | Description |
+| ----------------- | --------------------------------------- |
+| [`clear`](#clear) | Remove all entries from the table. |
+| [`count`](#count) | Return the number of keys in the table. |
**Copying**:
-| Function | Description |
-| ------------------------------ | ----------------------------------- |
-| [`copy(t)`](#fn-copyt) | Create a shallow copy of the table. |
-| [`deepcopy(v)`](#fn-deepcopyv) | Create a deep copy of a value. |
+| Function | Description |
+| ----------------------- | --------------------------------------------------------------------------------------------------------------------------- |
+| [`copy`](#copy) | Create a shallow copy of the table. |
+| [`deepcopy`](#deepcopy) | Create a deep copy of a value. If `v` is a table, all nested tables are copied recursively; other types are returned as-is. |
**Query**:
-| Function | Description |
-| --------------------------------------- | ------------------------------------------------------ |
-| [`filter(t, pred)`](#fn-filtert-pred) | Filter entries by a value predicate. |
-| [`find(t, v)`](#fn-findt-v) | Find the first key whose value equals the given value. |
-| [`find_if(t, pred)`](#fn-find_ift-pred) | Find first value and key matching predicate. |
-| [`get(t, ...)`](#fn-gett-varargs) | Safely get nested value by keys. |
+| Function | Description |
+| --------------------- | ---------------------------------------------------------------------------------- |
+| [`filter`](#filter) | Filter entries by a value predicate. |
+| [`find`](#find) | Find the first key whose value equals the given value. |
+| [`find_if`](#find-if) | Find first value and key matching predicate. |
+| [`get`](#get) | Safely get nested value by keys. If no keys are provided, returns the input table. |
**Transforms**:
-| Function | Description |
-| ----------------------------------- | ---------------------------------------------------------- |
-| [`invert(t)`](#fn-invertt) | Invert keys/values into new table. |
-| [`isempty(t)`](#fn-isemptyt) | Return true if table has no entries. |
-| [`keys(t)`](#fn-keyst) | Return a list of all keys in the table. |
-| [`map(t, fn)`](#fn-mapt-fn) | Return a new table by mapping each value (keys preserved). |
-| [`pairmap(t, fn)`](#fn-pairmapt-fn) | Return a new table by mapping each key-value pair. |
-| [`update(t1, t2)`](#fn-updatet1-t2) | Merge entries from t2 into t1 and return t1. |
-| [`values(t)`](#fn-valuest) | Return a list of all values in the table. |
-
-## Functions
+| Function | Description |
+| --------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
+| [`invert`](#invert) | Invert keys/values into new table. |
+| [`isempty`](#isempty) | Return true if table has no entries. |
+| [`keys`](#keys) | Return a list of all keys in the table. |
+| [`map`](#map) | Return a new table by mapping each value (keys preserved). |
+| [`pairmap`](#pairmap) | Return a new table by mapping each key-value pair. The resulting table keeps the same keys, with values transformed by `fn`. |
+| [`update`](#update) | Merge entries from t2 into t1 and return t1. |
+| [`values`](#values) | Return a list of all values in the table. |
### Basics
-#### `clear(t)` {#fn-cleart}
+Core table utilities for clearing and counting.
-Remove all entries from the table.
+#### `clear`
-::: code-group
-
-```lua [example.lua]
-local t = { a = 1, b = 2 }
-clear(t)
--- result: {}
-```
+Remove all entries from the table.
-```lua [signature.lua]
----@param t table
----@return nil
-function clear(t) end
+```lua
+t = { a = 1, b = 2 }
+clear(t) --> t = {}
```
-:::
-
-#### `count(t)` {#fn-countt}
+#### `count`
Return the number of keys in the table.
-::: code-group
-
-```lua [example.lua]
-local n = count({ a = 1, b = 2 })
--- result: 2
-```
-
-```lua [signature.lua]
----@param t table
----@return integer
----@nodiscard
-function count(t) end
+```lua
+n = count({ a = 1, b = 2 }) --> 2
```
-:::
-
### Copying
-#### `copy(t)` {#fn-copyt}
-
-Create a shallow copy of the table.
+Shallow and deep copy helpers.
-::: code-group
+#### `copy`
-```lua [example.lua]
-local t = copy({ a = 1, b = 2 })
--- result: { a = 1, b = 2 }
-```
+Create a shallow copy of the table.
-```lua [signature.lua]
----@generic T:table
----@param t T
----@return T
----@nodiscard
-function copy(t) end
+```lua
+t = copy({ a = 1, b = 2 }) --> { a = 1, b = 2 }
```
-:::
-
-#### `deepcopy(v)` {#fn-deepcopyv}
+#### `deepcopy`
Create a deep copy of a value. If `v` is a table, all nested tables are copied
recursively; other types are returned as-is.
-::: code-group
-
-```lua [example.lua]
-local n = deepcopy(42)
--- result: 42
-
-local t = deepcopy({ a = { b = 1 } })
--- result: { a = { b = 1 } }
+```lua
+t = deepcopy({ a = { b = 1 } }) --> { a = { b = 1 } }
+n = deepcopy(42) --> 42
```
-```lua [signature.lua]
----@generic T
----@param v T
----@return T
----@nodiscard
-function deepcopy(v) end
-```
-
-:::
-
### Query
-#### `filter(t, pred)` {#fn-filtert-pred}
-
-Filter entries by a value predicate.
+Read-only lookup and selection helpers.
-::: code-group
+#### `filter`
-```lua [example.lua]
-local even = filter({ a = 1, b = 2, c = 3 }, function(v)
- return v % 2 == 0
-end)
--- result: { b = 2 }
-```
+Filter entries by a value predicate.
-```lua [signature.lua]
----@param t table
----@param pred fun(v:any):boolean
----@return table
----@nodiscard
-function filter(t, pred) end
+```lua
+even = filter({ a = 1, b = 2, c = 3 }, function(v)
+ return v % 2 == 0
+end) --> { b = 2 }
```
-:::
-
-#### `find(t, v)` {#fn-findt-v}
+#### `find`
Find the first key whose value equals the given value.
-::: code-group
-
-```lua [example.lua]
-local key = find({ a = 1, b = 2, c = 2 }, 2)
--- result: "b" or "c"
+```lua
+key = find({ a = 1, b = 2, c = 2 }, 2) --> "b" or "c"
```
-```lua [signature.lua]
----@generic T1,T2
----@param t {[T1]:T2}
----@param v T2
----@return T1?
----@nodiscard
-function find(t, v) end
-```
-
-:::
-
-#### `find_if(t, pred)` {#fn-find_ift-pred}
+#### `find_if`
Find first value and key matching predicate.
-::: code-group
-
-```lua [example.lua]
-local v, k = find_if({ a = 1, b = 2 }, function(v, k)
- return k == "b" and v == 2
-end)
--- result: 2, "b"
+```lua
+v, k = find_if({ a = 1, b = 2 }, function(v, k)
+ return k == "b" and v == 2
+end) --> 2, "b"
```
-```lua [signature.lua]
----@generic T1,T2
----@param t table
----@param pred fun(v:T1,k:T2):boolean
----@return T1? v
----@return T2? k
----@nodiscard
-function find_if(t, pred) end
-```
-
-:::
-
-#### `get(t, ...)` {#fn-gett-varargs}
+#### `get`
Safely get nested value by keys. If no keys are provided, returns the input
table.
-::: code-group
-
-```lua [example.lua]
-local t = { a = { b = { c = 1 } } }
-local v = get(t, "a", "b", "c")
--- result: 1
-
-local v2 = get(t)
--- result: { a = { b = { c = 1 } } }
+```lua
+t = { a = { b = { c = 1 } } }
+v1 = get(t, "a", "b", "c") --> 1
+v2 = get(t) --> { a = { b = { c = 1 } } }
```
-```lua [signature.lua]
----@param t table
----@param ... any
----@return any
----@nodiscard
-function get(t, ...) end
-```
-
-:::
-
### Transforms
-#### `invert(t)` {#fn-invertt}
-
-Invert keys/values into new table.
+Table transformation and conversion utilities.
-::: code-group
+#### `invert`
-```lua [example.lua]
-local t = invert({ a = 1, b = 2 })
--- result: { [1] = "a", [2] = "b" }
-```
+Invert keys/values into new table.
-```lua [signature.lua]
----@generic T1,T2
----@param t {[T1]:T2}
----@return {[T2]:T1}
----@nodiscard
-function invert(t) end
+```lua
+t = invert({ a = 1, b = 2 }) --> { [1] = "a", [2] = "b" }
```
-:::
-
-#### `isempty(t)` {#fn-isemptyt}
+#### `isempty`
Return true if table has no entries.
-::: code-group
-
-```lua [example.lua]
-local empty = isempty({})
--- result: true
+```lua
+empty = isempty({}) --> true
```
-```lua [signature.lua]
----@param t table
----@return boolean
----@nodiscard
-function isempty(t) end
-```
-
-:::
-
-#### `keys(t)` {#fn-keyst}
+#### `keys`
Return a list of all keys in the table.
-::: code-group
-
-```lua [example.lua]
-local keys = keys({ a = 1, b = 2 })
--- result: { "a", "b" }
-```
-
-```lua [signature.lua]
----@generic T
----@param t {[any]:T}
----@return mods.List|T[]
----@nodiscard
-function keys(t) end
+```lua
+keys = keys({ a = 1, b = 2 }) --> { "a", "b" }
```
-:::
-
-#### `map(t, fn)` {#fn-mapt-fn}
+#### `map`
Return a new table by mapping each value (keys preserved).
-::: code-group
-
-```lua [example.lua]
-local t = map({ a = 1, b = 2 }, function(v)
- return v * 10
-end)
--- result: { a = 10, b = 20 }
-```
-
-```lua [signature.lua]
----@generic T1,T2,T3
----@param t {[T1]:T2}
----@param fn fun(v:T2):T3
----@return {[T1]:T3}
----@nodiscard
-function map(t, fn) end
+```lua
+t = map({ a = 1, b = 2 }, function(v)
+ return v * 10
+end) --> { a = 10, b = 20 }
```
-:::
-
-#### `pairmap(t, fn)` {#fn-pairmapt-fn}
+#### `pairmap`
Return a new table by mapping each key-value pair. The resulting table keeps the
same keys, with values transformed by `fn`.
-::: code-group
-
-```lua [example.lua]
-local t = pairmap({ a = 1, b = 2 }, function(k, v)
- return k .. v
-end)
--- result: { a = "a1", b = "b2" }
-```
-
-```lua [signature.lua]
----@generic T1,T2,T3
----@param t {[T1]:T2}
----@param fn fun(k:T1, v:T2):T3
----@return {[T1]:T3}
----@nodiscard
-function pairmap(t, fn) end
+```lua
+t = pairmap({ a = 1, b = 2 }, function(k, v)
+ return k .. v
+end) --> { a = "a1", b = "b2" }
```
-:::
-
-#### `update(t1, t2)` {#fn-updatet1-t2}
+#### `update`
Merge entries from t2 into t1 and return t1.
-::: code-group
-
-```lua [example.lua]
-local t1 = { a = 1, b = 2 }
-update(t1, { b = 3, c = 4 })
--- result: t1 is { a = 1, b = 3, c = 4 }
+```lua
+t1 = { a = 1, b = 2 }
+update(t1, { b = 3, c = 4 }) --> t1 is { a = 1, b = 3, c = 4 }
```
-```lua [signature.lua]
----@generic T:table
----@param t1 T
----@param t2 table
----@return T
----@nodiscard
-function update(t1, t2) end
-```
-
-:::
-
-#### `values(t)` {#fn-valuest}
+#### `values`
Return a list of all values in the table.
-::: code-group
-
-```lua [example.lua]
-local vals = values({ a = 1, b = 2 })
--- result: { 1, 2 }
-```
-
-```lua [signature.lua]
----@generic T
----@param t {[any]:T}
----@return mods.List|T[]
----@nodiscard
-function values(t) end
+```lua
+vals = values({ a = 1, b = 2 }) --> { 1, 2 }
```
-
-:::
diff --git a/docs/src/modules/template.md b/docs/src/modules/template.md
index c166c0a..a95234f 100644
--- a/docs/src/modules/template.md
+++ b/docs/src/modules/template.md
@@ -1,142 +1,90 @@
---
-description:
- Render lightweight templates with dot-path placeholders and function-aware
- values.
+desc:
+ "Render lightweight templates with dot-path placeholders and function-aware
+ values."
---
# `template`
-Render a simple template using the provided context.
-
-## Import
-
-```lua
-local mods = require("mods")
-local template = mods.template
-```
+Render lightweight templates with dot-path placeholders and function-aware
+values.
## Usage
```lua
-local view = {
- user = {
- name = "Ada",
- meta = { role = "Engineer" },
- name_func = function()
- return "Ada"
- end,
- },
- count = 3,
- name_func = function()
- return "Ada"
- end,
-}
-
-local out = template("Hello {{user.name}}!", view)
--- result: "Hello Ada!"
-
-out = template(view)
--- result:
--- {
--- count=3,
--- name_func=,
--- user={...}
--- }
-
-out = template("You have {{count}} new messages.", view)
--- result: "You have 3 new messages."
+template = require "mods.template"
-out = template('Missing key: "{{missing}}"', view)
--- result: 'Missing key: ""'
-
-out = template("Role: {{ user.meta.role }}", view)
--- result: "Role: Engineer"
-
-out = template("Hi {{name_func}}", view)
--- result: "Hi Ada"
+view = {
+ user = { name = "World" },
+}
-out = template("Stats: {{stats}}", { stats = { count = 3, ok = true } })
--- result:
--- Stats: {
--- count=3,
--- ok=true
--- }
+out = template("Hello {{user.name}}!", view) --> "Hello World!"
```
## Rules
- Placeholders use {{name}}.
- ```lua
- template("Hi {{name}}", { name = "Ada" })
- -- result: "Hi Ada"
- ```
+```lua
+template("Hi {{name}}", { name = "Ada" }) --> "Hi Ada"
+```
- Whitespace inside placeholders is ignored.
- ```lua
- template("Hi {{ name }}", { name = "Ada" })
- -- result: "Hi Ada"
- ```
+```lua
+template("Hi {{ name }}", { name = "Ada" }) --> "Hi Ada"
+```
- Dot paths are supported.
- ```lua
- template("Role: {{user.meta.role}}", {
- user = { meta = { role = "Engineer" } },
- }) -- result: "Role: Engineer"
- ```
+```lua
+template("Role: {{user.meta.role}}", {
+ user = { meta = { role = "Engineer" } },
+}) --> "Role: Engineer"
+```
- {{.}} resolves to the whole `view`.
- ```lua
- template("Value: {{.}}", 123)
- -- result: "Value: 123"
- ```
+```lua
+template("Value: {{.}}", 123) --> "Value: 123"
+```
- Function values are called and their return value is rendered.
- ```lua
- template("Hi {{name_func}}", {
- name_func = function()
- return "Ada"
- end,
- }) -- result: "Hi Ada"
- ```
+```lua
+template("Hi {{name_func}}", { name_func = function() return "Ada" end })
+--> "Hi Ada"
+```
- Table values render as first-depth key/value pairs. String values are quoted;
nested tables/functions are summarized.
- ```lua
- template("Data: {{data}}", { data = { a = 1, b = true } })
- -- result:
- -- Data: {
- -- a=1,
- -- b=true
- -- }
- ```
+```lua
+template("Data: {{data}}", { data = { a = 1, b = true } })
+--> {
+-- a = 1,
+-- b = true
+-- }
+```
- Missing keys render as an empty string.
- ```lua
- template("Missing: {{unknown}}", {})
- -- result: "Missing: "
- ```
+```lua
+template("Missing: {{unknown}}", {}) --> "Missing: "
+```
- If a tag is not closed ({{name), it is emitted as-is.
- ```lua
- template("Hi {{name", { name = "Ada" })
- -- result: "Hi {{name"
- ```
+```lua
+template("Hi {{name", { name = "Ada" }) --> "Hi {{name"
+```
- `template(view)` is shorthand for template("{{.}}", view).
- ```lua
- template({ a = 1, b = true })
- -- result:
- -- {
- -- a=1,
- -- b=true
- -- }
- ```
+```lua
+template({ a = 1, b = true })
+--> {
+-- a = 1,
+-- b = true
+-- }
+```
diff --git a/docs/src/modules/utils.md b/docs/src/modules/utils.md
index c87fe07..65d38bd 100644
--- a/docs/src/modules/utils.md
+++ b/docs/src/modules/utils.md
@@ -1,33 +1,26 @@
---
-description: Common utility helpers.
+desc: "Small shared utility helpers used by modules in this library."
---
# `utils`
-Common utility helpers.
+Small shared utility helpers used by modules in this library.
-## Import
+## Usage
```lua
-local utils = require("mods.utils")
-```
-
-## Quick Reference
+utils = require "mods.utils"
-| Function | Description |
-| -------------------------------------- | ----------------------------------------------------- |
-| [`quote(v)`](#fn-quotev) | Smart-quotes a string for readable Lua-like output. |
+print(utils.quote('hello "world"')) --> 'hello "world"'
+```
## Functions
-### `quote(v)` {#fn-quotev}
+### `quote`
-Smart-quotes a string for readable Lua-like output.
+Smart-quote a string for readable Lua-like output.
```lua
-print(utils.quote('He said "hi"'))
--- 'He said "hi"'
-
-print(utils.quote([[say "hi" and 'bye']]))
--- "say \"hi\" and 'bye'"
+print(utils.quote('He said "hi"')) -- 'He said "hi"'
+print(utils.quote('say "hi" and \\'bye\\'')) -- "say \"hi\" and 'bye'"
```
diff --git a/docs/src/modules/validate.md b/docs/src/modules/validate.md
index 3c6ff65..8da88fd 100644
--- a/docs/src/modules/validate.md
+++ b/docs/src/modules/validate.md
@@ -1,84 +1,70 @@
---
-description:
- Validate Lua values and path kinds with flexible aliases and customizable
- messages.
+desc: "Validation checks for values and filesystem path types."
---
# `validate`
Validation checks for values and filesystem path types.
-## Import
-
-```lua
-local mods = require("mods")
-local validate = mods.validate
-```
-
## Usage
-```lua
-local ok, err = validate.is.number("nope")
--- result: false, "expected number, got string"
+```lua [.lua]
+validate= require "mods.validate"
+
+ok, err = validate.is.number("nope")
+--> false, "expected number, got string"
ok, err = validate.is_not.number(3.14)
--- result: false, "expected not number"
+--> false, "expected not number"
```
-> [!NOTE]
->
-> When called without an explicit type (`validate(v, tp)`), `validate` defaults
-> to checking `nil`. `validate()` is equivalent to `validate(nil, "nil")`, so it
-> passes. `validate(1)` is equivalent to `validate(1, "nil")`, so it fails with
-> `expected nil, got number`.
-
-
-
> [!IMPORTANT]
>
-> Validator access is case-insensitive.
+> Behavior without `tp`:
>
-> - `validate.is.number`, `validate.IS.Number`, and `validate.I_s.NuMbEr` are
-> equivalent.
-> - Top-level aliases are underscore-insensitive too: `validate.is_number`,
-> `validate.IS_NUMBER`, and `validate.isnumber` are equivalent.
-> - Negated validators can be accessed as `is_not`, `isnot`, `isNot`, `not`, or
-> `Not`. Example: `validate.is_not.number`, `validate.isNot.number`,
-> `validate.isnot.number`, `validate.not.number`, `validate.is_not_number`,
-> `validate.isnotnumber`.
+> - `validate()` is equivalent to `validate(nil, "nil")` (passes)
+> - `validate(1)` is equivalent to `validate(1, "nil")` (fails with
+> `expected nil, got number`)
+>
+> Validator access is case-insensitive:
+>
+> - `validate.is.number` and `validate.IS.Number` are equivalent.
+> - Top-level aliases are underscore-insensitive: `validate.is_number`,
+> `validate.IS_NUMBER`, and `validate.isnumber`.
+> - Negated validators are available via `is_not`, `isnot`, `isNot`, `not`, and
+> `Not`, including underscore-insensitive top-level aliases (for example,
+> `validate.is_not_number` and `validate.isnotnumber`).
## Callable Forms
-All three are callable:
-
-- `validate(v, tp?)`
-- `validate.is(v, tp?)`
-- `validate.is_not(v, tp?)`
-
-Callable access is also alias/case flexible:
-
-- `validate.is`, `validate.IS`
-- `validate.is_not`, `validate.isnot`, `validate.isNot`, `validate.not`,
- `validate.Not`
+`validate`, `validate.is`, and `validate.is_not` are all callable.
```lua
-local ok, err
-
-ok, err = validate(1, "number") -- true
-ok, err = validate.is(1, "number") -- true
-ok, err = validate.IS(1, "number") -- true
-ok, err = validate.is_not(1, "number") -- false, "expected not number"
-ok, err = validate.Not(1, "number") -- false, "expected not number"
+ok, err = validate(1, "number") --> true, nil
+ok, err = validate.is("x", "string") --> true, nil
+ok, err = validate.is_not(1, "number") --> false, "expected not number"
```
-## Quick Reference
-
-| Area | Common checks |
-| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| `is` (type) | [`boolean`](#is-boolean), [`function`](#is-function), [`nil`](#is-nil), [`number`](#is-number), [`string`](#is-string), [`table`](#is-table), [`thread`](#is-thread), [`userdata`](#is-userdata) |
-| `is` (value) | [`false`](#is-false), [`true`](#is-true), [`falsy`](#is-falsy), [`callable`](#is-callable), [`integer`](#is-integer), [`truthy`](#is-truthy) |
-| `is` (path) | [`block`](#is-block), [`char`](#is-char), [`device`](#is-device), [`dir`](#is-dir), [`fifo`](#is-fifo), [`file`](#is-file), [`link`](#is-link), [`socket`](#is-socket) |
-| `is_not` (type/value) | [`boolean`](#is-not-boolean), [`function`](#is-not-function), [`nil`](#is-not-nil), [`number`](#is-not-number), [`string`](#is-not-string), [`table`](#is-not-table), [`thread`](#is-not-thread), [`userdata`](#is-not-userdata), [`false`](#is-not-false), [`true`](#is-not-true), [`falsy`](#is-not-falsy), [`callable`](#is-not-callable), [`integer`](#is-not-integer), [`truthy`](#is-not-truthy) |
+> [!IMPORTANT]
+>
+> When `tp` is omitted, the default check is `"nil"`:
+>
+> - `validate()` is equivalent to `validate(nil, "nil")` (passes)
+> - `validate(1)` is equivalent to `validate(1, "nil")` (fails)
+>
+> Callable namespace aliases are case-insensitive, and negated aliases are
+> underscore-insensitive:
+>
+> - `validate.is`, `validate.IS`
+> - `validate.is_not`, `validate.isnot`, `validate.isNot`, `validate["not"]`,
+> `validate.Not`
+>
+> ```lua
+> validate.is(1, "number") --> true
+> validate.IS(1, "number") --> true
+> validate.is_not(1, "number") --> false, "expected not number"
+> validate.Not(1, "number") --> false, "expected not number"
+> ```
## Custom Messages
@@ -105,11 +91,11 @@ Available placeholders:
validate.messages.positive.number = "need {{expected}}, got {{got}} (value={{value}})"
validate.messages.negative.number = "must not be {{expected}} (value={{value}})"
-local ok, err = validate.is.number("x")
--- result: false, 'need number, got string (value="x")'
+ok, err = validate.is.number("x")
+--> false, 'need number, got string (value="x")'
ok, err = validate.is_not.number(42)
--- result: false, "must not be number (value=42)"
+--> false, "must not be number (value=42)"
```
## Default Messages
@@ -144,429 +130,425 @@ validate.on_fail = function(errmsg)
return "custom failure"
end
-local ok, err = validate.number("x")
--- prints: validation failed: expected number, got string
--- result: false, "custom failure"
+ok, err = validate.number("x")
+--> prints -> validation failed: expected number, got string
+--> false, "custom failure"
```
## Functions
-### `is`
+**Type Checks**:
-Positive validators. These checks pass only when the value matches the expected
-type or check.
+| Function | Description |
+| ------------------------------- | ---------------------------------------------------------------------------------------------- |
+| [`boolean`](#boolean) | Returns `true` when `v` is a boolean. Otherwise returns `false` and an error message. |
+| [`function`](#function) | Returns `true` when `v` is a function. Otherwise returns `false` and an error message. |
+| [`nil`](#nil) | Returns `true` when `v` is `nil`. Otherwise returns `false` and an error message. |
+| [`number`](#number) | Returns `true` when `v` is a number. Otherwise returns `false` and an error message. |
+| [`string`](#string) | Returns `true` when `v` is a string. Otherwise returns `false` and an error message. |
+| [`table`](#table) | Returns `true` when `v` is a table. Otherwise returns `false` and an error message. |
+| [`thread`](#thread) | Returns `true` when `v` is a thread. Otherwise returns `false` and an error message. |
+| [`userdata`](#userdata) | Returns `true` when `v` is userdata. Otherwise returns `false` and an error message. |
+| [`not_boolean`](#not-boolean) | Returns `true` when `v` is **not** a boolean. Otherwise returns `false` and an error message. |
+| [`not_function`](#not-function) | Returns `true` when `v` is **not** a function. Otherwise returns `false` and an error message. |
+| [`not_nil`](#not-nil) | Returns `true` when `v` is **not** `nil`. Otherwise returns `false` and an error message. |
+| [`not_number`](#not-number) | Returns `true` when `v` is **not** a number. Otherwise returns `false` and an error message. |
+| [`not_string`](#not-string) | Returns `true` when `v` is **not** a string. Otherwise returns `false` and an error message. |
+| [`not_table`](#not-table) | Returns `true` when `v` is **not** a table. Otherwise returns `false` and an error message. |
+| [`not_thread`](#not-thread) | Returns `true` when `v` is **not** a thread. Otherwise returns `false` and an error message. |
+| [`not_userdata`](#not-userdata) | Returns `true` when `v` is **not** userdata. Otherwise returns `false` and an error message. |
-#### Negated Type Checks
+**Value Checks**:
-Lua type validators for [`boolean`](#is-boolean), [`function`](#is-function),
-[`nil`](#is-nil), [`number`](#is-number), [`string`](#is-string),
-[`table`](#is-table), [`thread`](#is-thread), and [`userdata`](#is-userdata).
+| Function | Description |
+| ------------------------------- | --------------------------------------------------------------------------------------------------- |
+| [`false`](#false) | Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an error message. |
+| [`true`](#true) | Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an error message. |
+| [`falsy`](#falsy) | Returns `true` when `v` is falsy. Otherwise returns `false` and an error message. |
+| [`callable`](#callable) | Returns `true` when `v` is callable. Otherwise returns `false` and an error message. |
+| [`integer`](#integer) | Returns `true` when `v` is an integer. Otherwise returns `false` and an error message. |
+| [`truthy`](#truthy) | Returns `true` when `v` is truthy. Otherwise returns `false` and an error message. |
+| [`not_false`](#not-false) | Returns `true` when `v` is **not** exactly `false`. Otherwise returns `false` and an error message. |
+| [`not_true`](#not-true) | Returns `true` when `v` is **not** exactly `true`. Otherwise returns `false` and an error message. |
+| [`not_falsy`](#not-falsy) | Returns `true` when `v` is **not** falsy. Otherwise returns `false` and an error message. |
+| [`not_callable`](#not-callable) | Returns `true` when `v` is **not** callable. Otherwise returns `false` and an error message. |
+| [`not_integer`](#not-integer) | Returns `true` when `v` is **not** an integer. Otherwise returns `false` and an error message. |
+| [`not_truthy`](#not-truthy) | Returns `true` when `v` is **not** truthy. Otherwise returns `false` and an error message. |
-##### `boolean(v)` {#is-boolean}
+**Path Checks**:
-Returns `true` when `v` is a Lua boolean.
+| Function | Description |
+| ------------------- | ------------------------------------------------------------------------------------------------------- |
+| [`block`](#block) | Returns `true` when `v` is a block device path. Otherwise returns `false` and an error message. |
+| [`char`](#char) | Returns `true` when `v` is a char device path. Otherwise returns `false` and an error message. |
+| [`device`](#device) | Returns `true` when `v` is a block or char device path. Otherwise returns `false` and an error message. |
+| [`dir`](#dir) | Returns `true` when `v` is a directory path. Otherwise returns `false` and an error message. |
+| [`fifo`](#fifo) | Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error message. |
+| [`file`](#file) | Returns `true` when `v` is a file path. Otherwise returns `false` and an error message. |
+| [`link`](#link) | Returns `true` when `v` is a symlink path. Otherwise returns `false` and an error message. |
+| [`socket`](#socket) | Returns `true` when `v` is a socket path. Otherwise returns `false` and an error message. |
-```lua
-local ok, err = validate.is.boolean(true) -- true
-ok, err = validate.is.boolean(1)
--- result: false, "expected boolean, got number"
-```
+### Type Checks
+
+Basic Lua type validators (and their negated variants).
-##### `function(v)` {#is-function}
+#### `boolean`
-Returns `true` when `v` is a function value.
+Returns `true` when `v` is a boolean. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.Function(function() end) -- true
-ok, err = validate.is.Function("hello")
--- result: false, "expected function, got string"
+ok, err = validate.is.boolean(true) --> true, nil
+ok, err = validate.is.boolean(1) --> false, "expected boolean, got number"
```
-##### `nil(v)` {#is-nil}
+#### `function`
-Returns `true` when `v` is `nil`.
+Returns `true` when `v` is a function. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.Nil(nil) -- true
-ok, err = validate.is.Nil(0)
--- result: false, "expected nil, got number"
+ok, err = validate.is.Function(function() end) --> true, nil
+ok, err = validate.is.Function(1)
+--> false, "expected function, got number"
```
-##### `number(v)` {#is-number}
+#### `nil`
-Returns `true` when `v` is a number.
+Returns `true` when `v` is `nil`. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.number(3.14) -- true
-ok, err = validate.is.number("3.14")
--- result: false, "expected number, got string"
+ok, err = validate.is.Nil(nil) --> true, nil
+ok, err = validate.is.Nil(0) --> false, "expected nil, got number"
```
-##### `string(v)` {#is-string}
+#### `number`
-Returns `true` when `v` is a string.
+Returns `true` when `v` is a number. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.string("hello") -- true
-ok, err = validate.is.string(false)
--- result: false, "expected string, got boolean"
+ok, err = validate.is.number(42) --> true, nil
+ok, err = validate.is.number("x") --> false, "expected number, got string"
```
-##### `table(v)` {#is-table}
+#### `string`
-Returns `true` when `v` is a table.
+Returns `true` when `v` is a string. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.table({}) -- true
-ok, err = validate.is.table("x")
--- result: false, "expected table, got string"
+ok, err = validate.is.string("hello") --> true, nil
+ok, err = validate.is.string(1) --> false, "expected string, got number"
```
-##### `thread(v)` {#is-thread}
+#### `table`
-Returns `true` when `v` is a coroutine thread.
+Returns `true` when `v` is a table. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.thread(coroutine.create(function() end)) -- true
-ok, err = validate.is.thread(function() end)
--- result: false, "expected thread, got function"
+ok, err = validate.is.table({}) --> true, nil
+ok, err = validate.is.table(1) --> false, "expected table, got number"
```
-##### `userdata(v)` {#is-userdata}
+#### `thread`
-Returns `true` when `v` is a userdata value.
+Returns `true` when `v` is a thread. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.userdata(io.stdout) -- true
-ok, err = validate.is.userdata({})
--- result: false, "expected userdata, got table"
+co = coroutine.create(function() end)
+ok, err = validate.is.thread(co) --> true, nil
+ok, err = validate.is.thread(1) --> false, "expected thread, got number"
```
-#### Negated Value Checks
-
-Validators for common truth/value semantics.
+#### `userdata`
-##### `false(v)` {#is-false}
-
-Returns `true` when `v` is exactly `false`.
+Returns `true` when `v` is userdata. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.False(false) -- true
-ok, err = validate.is.False(true)
--- result: false, "expected false, got true"
+ok, err = validate.is.userdata(io.stdout) --> true, nil
+ok, err = validate.is.userdata(1) --> false, "expected userdata, got number"
```
-##### `true(v)` {#is-true}
+#### `not_boolean`
-Returns `true` when `v` is exactly `true`.
+Returns `true` when `v` is **not** a boolean. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.True(true) -- true
-ok, err = validate.is.True(false)
--- result: false, "expected true, got false"
+ok, err = validate.is_not.boolean(1) --> true, nil
+ok, err = validate.is_not.boolean(true) --> false, "expected not boolean"
```
-##### `falsy(v)` {#is-falsy}
+#### `not_function`
-Returns `true` when `v` is `false` or `nil`.
+Returns `true` when `v` is **not** a function. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.falsy(false) -- true
-ok, err = validate.is.falsy(1)
--- result: false, "expected falsy, got number"
+ok, err = validate.is_not.Function(1) --> true, nil
+ok, err = validate.is_not.Function(function() end) --> false, "expected not function"
```
-##### `callable(v)` {#is-callable}
+#### `not_nil`
-Returns `true` when `v` can be called (function or callable table).
+Returns `true` when `v` is **not** `nil`. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.callable(function() end) -- true
-ok, err = validate.is.callable({})
--- result: false, "expected callable, got table"
+ok, err = validate.is_not.Nil(0) --> true, nil
+ok, err = validate.is_not.Nil(nil) --> false, "expected not nil"
```
-##### `integer(v)` {#is-integer}
+#### `not_number`
-Returns `true` when `v` is a whole number.
+Returns `true` when `v` is **not** a number. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.integer(42) -- true
-ok, err = validate.is.integer(4.2)
--- result: false, "expected integer, got 4.2"
+ok, err = validate.is_not.number("x") --> true, nil
+ok, err = validate.is_not.number(42) --> false, "expected not number"
```
-##### `truthy(v)` {#is-truthy}
+#### `not_string`
-Returns `true` when `v` is neither `false` nor `nil`.
+Returns `true` when `v` is **not** a string. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.truthy("non-empty") -- true
-ok, err = validate.is.truthy(nil)
--- result: false, "expected truthy, got nil"
+ok, err = validate.is_not.string(1) --> true, nil
+ok, err = validate.is_not.string("hello") --> false, "expected not string"
```
-#### Path Checks
+#### `not_table`
-Filesystem kind validators for paths.
-
-> [!IMPORTANT]
->
-> Path checks require LuaFileSystem
-> ([`lfs`](https://github.com/lunarmodules/luafilesystem)).
->
-> These functions raise an error if `lfs` is not installed.
-
-##### `block(path)` {#is-block}
-
-Returns `true` when `path` points to a block device.
+Returns `true` when `v` is **not** a table. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.block("/dev/sda") -- true
-ok, err = validate.is.block(false)
--- result: false, "false is not a valid block path"
-ok, err = validate.is.block("/dev/null")
--- result: false, '"/dev/null" is not a valid block path'
+ok, err = validate.is_not.table(1) --> true, nil
+ok, err = validate.is_not.table({}) --> false, "expected not table"
```
-##### `char(path)` {#is-char}
+#### `not_thread`
-Returns `true` when `path` points to a character device.
+Returns `true` when `v` is **not** a thread. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.char("/dev/null") -- true
-ok, err = validate.is.char(nil)
--- result: false, "nil is not a valid char path"
-ok, err = validate.is.char("/tmp")
--- result: false, '"/tmp" is not a valid char path'
+co = coroutine.create(function() end)
+ok, err = validate.is_not.thread(1) --> true, nil
+ok, err = validate.is_not.thread(co) --> false, "expected not thread"
```
-##### `device(path)` {#is-device}
+#### `not_userdata`
-Returns `true` when `path` points to any device node.
+Returns `true` when `v` is **not** userdata. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.device("/dev/null") -- true
-ok, err = validate.is.device(true)
--- result: false, "true is not a valid device path"
-ok, err = validate.is.device("README.md")
--- result: false, '"README.md" is not a valid device path'
+ok, err = validate.is_not.userdata(1) --> true, nil
+ok, err = validate.is_not.userdata(io.stdout) --> false, "expected not userdata"
```
-##### `dir(path)` {#is-dir}
+### Value Checks
+
+Value-state validators (exact true/false, truthy/falsy, callable, integer).
-Returns `true` when `path` points to a directory.
+#### `false`
+
+Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.dir("/tmp") -- true
-ok, err = validate.is.dir(0)
--- result: false, "0 is not a valid dir path"
-ok, err = validate.is.dir("README.md")
--- result: false, '"README.md" is not a valid dir path'
+ok, err = validate.is.False(false) --> true, nil
+ok, err = validate.is.False(true) --> false, "expected false, got true"
```
-##### `fifo(path)` {#is-fifo}
+#### `true`
-Returns `true` when `path` points to a FIFO (named pipe).
+Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is.fifo("/path/to/fifo") -- true
-ok, err = validate.is.fifo(7)
--- result: false, "7 is not a valid fifo path"
-ok, err = validate.is.fifo("README.md")
--- result: false, '"README.md" is not a valid fifo path'
+ok, err = validate.is.True(true) --> true, nil
+ok, err = validate.is.True(false) --> false, "expected true, got false"
```
-##### `file(path)` {#is-file}
+#### `falsy`
-Returns `true` when `path` points to a regular file.
+Returns `true` when `v` is falsy. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.file("README.md") -- true
-ok, err = validate.is.file(42)
--- result: false, "42 is not a valid file path"
-ok, err = validate.is.file("src")
--- result: false, '"src" is not a valid file path'
+ok, err = validate.is.falsy(false) --> true, nil
+ok, err = validate.is.falsy(1) --> false, "expected falsy, got number"
```
-##### `link(path)` {#is-link}
+#### `callable`
-Returns `true` when `path` points to a symbolic link.
+Returns `true` when `v` is callable. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.link("/path/to/link") -- true
-ok, err = validate.is.link(99)
--- result: false, "99 is not a valid link path"
-ok, err = validate.is.link("README.md")
--- result: false, '"README.md" is not a valid link path'
+ok, err = validate.is.callable(type) --> true, nil
+ok, err = validate.is.callable(1) --> false, "expected callable, got number"
```
-##### `socket(path)` {#is-socket}
+#### `integer`
-Returns `true` when `path` points to a socket.
+Returns `true` when `v` is an integer. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is.socket("/path/to/socket") -- true
-ok, err = validate.is.socket(500)
--- result: false, "500 is not a valid socket path"
-ok, err = validate.is.socket("README.md")
--- result: false, '"README.md" is not a valid socket path'
+ok, err = validate.is.integer(1) --> true, nil
+ok, err = validate.is.integer(1.5) --> false, "expected integer, got 1.5"
```
-### `is_not`
-
-Negated validators. These checks pass only when the value does not match the
-expected type or check.
-
-> [!IMPORTANT]
->
-> `is_not` supports type and value checks. Path checks are available on
-> [`is`](#is) only.
+#### `truthy`
-#### Type Checks
+Returns `true` when `v` is truthy. Otherwise returns `false` and an error
+message.
-Negated Lua type validators.
+```lua
+ok, err = validate.is.truthy(1) --> true, nil
+ok, err = validate.is.truthy(false) --> false, "expected truthy, got boolean"
+```
-##### `boolean(v)` {#is-not-boolean}
+#### `not_false`
-Returns `true` when `v` is not a Lua boolean.
+Returns `true` when `v` is **not** exactly `false`. Otherwise returns `false`
+and an error message.
```lua
-local ok, err = validate.is_not.boolean(123) -- true
-ok, err = validate.is_not.boolean(true)
--- result: false, "expected not boolean"
+ok, err = validate.is_not.False(true) --> true, nil
+ok, err = validate.is_not.False(false) --> false, "expected not false"
```
-##### `function(v)` {#is-not-function}
+#### `not_true`
-Returns `true` when `v` is not a function value.
+Returns `true` when `v` is **not** exactly `true`. Otherwise returns `false` and
+an error message.
```lua
-local ok, err = validate.is_not.Function("abc") -- true
-ok, err = validate.is_not.Function(function() end)
--- result: false, "expected not function"
+ok, err = validate.is_not.True(false) --> true, nil
+ok, err = validate.is_not.True(true) --> false, "expected not true"
```
-##### `nil(v)` {#is-not-nil}
+#### `not_falsy`
-Returns `true` when `v` is not `nil`.
+Returns `true` when `v` is **not** falsy. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is_not.Nil(123) -- true
-ok, err = validate.is_not.Nil(nil)
--- result: false, "expected not nil"
+ok, err = validate.is_not.falsy(1) --> true, nil
+ok, err = validate.is_not.falsy(false) --> false, "expected not falsy"
```
-##### `number(v)` {#is-not-number}
+#### `not_callable`
-Returns `true` when `v` is not a number.
+Returns `true` when `v` is **not** callable. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is_not.number("3.14") -- true
-ok, err = validate.is_not.number(3.14)
--- result: false, "expected not number"
+ok, err = validate.is_not.callable(1) --> true, nil
+ok, err = validate.is_not.callable(function() end) --> false, "expected not callable"
```
-##### `string(v)` {#is-not-string}
+#### `not_integer`
-Returns `true` when `v` is not a string.
+Returns `true` when `v` is **not** an integer. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is_not.string(false) -- true
-ok, err = validate.is_not.string("hello")
--- result: false, "expected not string"
+ok, err = validate.is_not.integer(1.5) --> true, nil
+ok, err = validate.is_not.integer(1) --> false, "expected non-integer, got 1"
```
-##### `table(v)` {#is-not-table}
+#### `not_truthy`
-Returns `true` when `v` is not a table.
+Returns `true` when `v` is **not** truthy. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is_not.table(false) -- true
-ok, err = validate.is_not.table({})
--- result: false, "expected not table"
+ok, err = validate.is_not.truthy(false) --> true, nil
+ok, err = validate.is_not.truthy(1) --> false, "expected not truthy"
```
-##### `thread(v)` {#is-not-thread}
+### Path Checks
+
+#### `block`
-Returns `true` when `v` is not a coroutine thread.
+Returns `true` when `v` is a block device path. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is_not.thread(function() end) -- true
-ok, err = validate.is_not.thread(coroutine.create(function() end))
--- result: false, "expected not thread"
+ok, err = validate.is.block(".")
```
-##### `userdata(v)` {#is-not-userdata}
+#### `char`
-Returns `true` when `v` is not a userdata value.
+Returns `true` when `v` is a char device path. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is_not.userdata({}) -- true
-ok, err = validate.is_not.userdata(io.stdout)
--- result: false, "expected not userdata"
+ok, err = validate.is.char(".")
```
-#### Value Checks
-
-Negated validators for common truth/value semantics.
-
-##### `false(v)` {#is-not-false}
+#### `device`
-Returns `true` when `v` is not exactly `false`.
+Returns `true` when `v` is a block or char device path. Otherwise returns
+`false` and an error message.
```lua
-local ok, err = validate.is_not.False(true) -- true
-ok, err = validate.is_not.False(false)
--- result: false, "expected not false"
+ok, err = validate.is.device(".")
```
-##### `true(v)` {#is-not-true}
+#### `dir`
-Returns `true` when `v` is not exactly `true`.
+Returns `true` when `v` is a directory path. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is_not.True(false) -- true
-ok, err = validate.is_not.True(true)
--- result: false, "expected not true"
+ok, err = validate.is.dir(".")
```
-##### `falsy(v)` {#is-not-falsy}
+#### `fifo`
-Returns `true` when `v` is neither `false` nor `nil`.
+Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is_not.falsy(true) -- true
-ok, err = validate.is_not.falsy(nil)
--- result: false, "expected not falsy"
+ok, err = validate.is.fifo(".")
```
-##### `callable(v)` {#is-not-callable}
+#### `file`
-Returns `true` when `v` cannot be called.
+Returns `true` when `v` is a file path. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is_not.callable({}) -- true
-ok, err = validate.is_not.callable(function() end)
--- result: false, "expected not callable"
+ok, err = validate.is.file(".")
```
-##### `integer(v)` {#is-not-integer}
+#### `link`
-Returns `true` when `v` is not a whole number.
+Returns `true` when `v` is a symlink path. Otherwise returns `false` and an
+error message.
```lua
-local ok, err = validate.is_not.integer(13.4) -- true
-ok, err = validate.is_not.integer(13)
--- result: false, "expected non-integer, got 13"
+ok, err = validate.is.link(".")
```
-##### `truthy(v)` {#is-not-truthy}
+#### `socket`
-Returns `true` when `v` is `false` or `nil`.
+Returns `true` when `v` is a socket path. Otherwise returns `false` and an error
+message.
```lua
-local ok, err = validate.is_not.truthy(nil) -- true
-ok, err = validate.is_not.truthy(1)
--- result: false, "expected not truthy"
+ok, err = validate.is.socket(".")
```