slang-ts 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -107,7 +107,7 @@ import { option, Ok, Err, atom, match } from "slang-ts";
107
107
  - [println][logging] (with `setEnvironment`)
108
108
  - [createStepper][stepper]
109
109
 
110
- Full reference: [docs index][docs-index]. Feature list: [CHANGELOG.md][changelog].
110
+ Full reference: [docs index][docs-index]. Feature list: [CHANGELOG.md][changelog]. Agent guide: [skill/SKILL.md](skill/SKILL.md).
111
111
 
112
112
  ## Real-world examples
113
113
 
@@ -287,3 +287,4 @@ MIT License. See [LICENSE][license].
287
287
  [docs-index]: https://github.com/Hussseinkizz/slang/blob/main/docs/README.md
288
288
  [changelog]: https://github.com/Hussseinkizz/slang/blob/main/CHANGELOG.md
289
289
  [license]: https://github.com/Hussseinkizz/slang/blob/main/LICENSE
290
+ [skill]: https://github.com/Hussseinkizz/slang/blob/main/skill/SKILL.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slang-ts",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Functional programming utilities for TypeScript: Option, Result, SafeTry, pattern matching, async control, and data helpers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,6 +15,7 @@
15
15
  "types": "dist/index.d.ts",
16
16
  "files": [
17
17
  "dist",
18
+ "skill",
18
19
  "CHANGELOG.md"
19
20
  ],
20
21
  "engines": {
package/skill/SKILL.md ADDED
@@ -0,0 +1,164 @@
1
+ # slang-ts agent skill
2
+
3
+ This skill tells AI agents how to work with slang-ts — its APIs, patterns, and conventions — so agents can write correct TypeScript against it.
4
+
5
+ ## What slang-ts is
6
+
7
+ slang-ts is a zero-dependency functional programming library for TypeScript. It brings Rust- and Erlang-style utilities: `Option`, `Result`, `SafeTry`, pattern matching (`match`/`matchAll`), async control (`SuperPromise`, `SuperRunner`, `taskGroup`, `Signal`, `Channel`), and data helpers (`list`, `struct`, `sets`, `Ok.iterate`, `memoized`, `zip`, `pipe`, `atom`, `to`).
8
+
9
+ Import only what you use:
10
+
11
+ ```ts
12
+ import { option, Ok, Err, match, superPromise, list } from "slang-ts";
13
+ ```
14
+
15
+ ## Core wrappers
16
+
17
+ ### Option
18
+
19
+ `option(value)` → `Some(value)` or `None`. `0` and `false` count as present; `null`, `undefined`, `""`, `NaN`, and `Infinity` are `None`.
20
+
21
+ ```ts
22
+ const port = option(process.env.PORT).unwrap().else(3000);
23
+ ```
24
+
25
+ Never read `.value` on `None`. Check `.isSome` / `.isNone` first, or use `.unwrap().else(fallback)`.
26
+
27
+ ### Result
28
+
29
+ `Ok(value, message?)` / `Err(error)`. Failures travel as values, not throws.
30
+
31
+ ```ts
32
+ function divide(a: number, b: number): Result<number, string> {
33
+ return b === 0 ? Err("Cannot divide by zero") : Ok(a / b);
34
+ }
35
+ ```
36
+
37
+ Branch with `if (result.isOk) { ... } else { ... }`. Finish chains with `.unwrap().else(fallback)` or `.unwrap().panic(message?)`.
38
+
39
+ `Err(error, raw?)` keeps the original cause on the non-enumerable `.raw` for logs; `.error` stays human-readable.
40
+
41
+ ### match / matchAll
42
+
43
+ `match(result, { Ok: ..., Err: ... })` is exhaustive — TypeScript requires both cases.
44
+
45
+ `matchAll` is for strings, numbers, booleans, symbols, and `Atom`s. It always needs a `_` fallback since there's no finite set of cases.
46
+
47
+ ```ts
48
+ const message = matchAll(failed.category, {
49
+ OUT_OF_BOUNDS: () => "That page is out of range.",
50
+ _: (category) => `Unexpected failure: ${category}`,
51
+ });
52
+ ```
53
+
54
+ ## Collection chains (list, struct, sets, Ok.iterate)
55
+
56
+ These return a `Fallible<T>`, not a plain `Result`. Finish with `.else(fallback)` or `.panic(message?)`. On failure, `.category` holds a string like `"OUT_OF_BOUNDS"` or `"INVALID_INPUT"`.
57
+
58
+ ```ts
59
+ const failed = list([1, 2, 3]).range(1, 99).take(1);
60
+ if (failed.category === "OUT_OF_BOUNDS") {
61
+ println(failed.else([])); // []
62
+ } else {
63
+ failed.panic(failed.category);
64
+ }
65
+ ```
66
+
67
+ - `get` already takes a fallback: `get(key, fallback)`. Do not pair `get(x, fallback)` with `.else(fallback)` — that's redundant.
68
+ - `.panic()` throws; once you panic, no custom user message is read afterward.
69
+
70
+ ### list
71
+
72
+ Strict indexed arrays with `get`, `take`, `skip`, `range`, `chunk`, `count`, `prune`. Bounds are strict — out-of-range fails instead of clamping.
73
+
74
+ ```ts
75
+ const page = list(users).range(start, end).else([]);
76
+ ```
77
+
78
+ ### struct
79
+
80
+ Safe record access and shaping. `get`, `pick`, `omit`, `merge`, `countBy`, `keyBy`.
81
+
82
+ ```ts
83
+ const port = struct(config).get(["server", "port"], 3000);
84
+ ```
85
+
86
+ ### sets
87
+
88
+ Membership and set algebra. `has`, `unique`, `union`, `intersection`, `difference`. Objects compare by identity; primitives by value.
89
+
90
+ ### Ok.iterate
91
+
92
+ Lazy pipelines over a successful `Ok`. `map`, `filter`, `flatMap`, `take`, `drop`, `chunk`, then `reduce`, `count`, or `toArray`.
93
+
94
+ ```ts
95
+ const names = Ok(users)
96
+ .iterate()
97
+ .filter((u) => u.active)
98
+ .map((u) => u.name)
99
+ .toArray()
100
+ .else([]);
101
+ ```
102
+
103
+ ## Async
104
+
105
+ ### SuperPromise
106
+
107
+ One async operation with timeout, retry, cancellation, and `Ok`/`Err` settlement. Your function gets an `AbortSignal`.
108
+
109
+ ```ts
110
+ const user = await superPromise(
111
+ async (signal) => {
112
+ const response = await fetch(`/api/users/${id}`, { signal });
113
+ return response.json();
114
+ },
115
+ { timeout: 5000, retry: 2 },
116
+ );
117
+ ```
118
+
119
+ ### SuperRunner
120
+
121
+ Run `SuperPromise`s in sequence, parallel, or race. `start()` runs once.
122
+
123
+ ```ts
124
+ const all = superRunner({ type: "all", runners: { a, b } });
125
+ const result = await all.start();
126
+ ```
127
+
128
+ ### taskGroup
129
+
130
+ Shared concurrency limit and start spacing across tasks. Retries wait for a new slot.
131
+
132
+ ```ts
133
+ const api = taskGroup("user-api", { concurrency: 3, throttle: 200 });
134
+ const task = superPromise(fetchUsers, { group: api });
135
+ ```
136
+
137
+ ### Signal / Channel
138
+
139
+ `createSignal()` — a trigger that fires once (`fire()`), AbortSignal-compatible.
140
+
141
+ `createChannel()` — in-process publish/subscribe. `subscribe(topic, handler)` returns an unsubscribe function.
142
+
143
+ ## Other utilities
144
+
145
+ - `atom("name")` — unique symbol with a readable description; matches in `matchAll` by description.
146
+ - `to` — convert between `Option`, `Atom`, `Result` (e.g. `option("ready").to("atom")`).
147
+ - `pipe` — run `Result`-returning steps in order, stopping at the first failure.
148
+ - `zip` / `zipWith` / `unzip` — combine parallel collections.
149
+ - `memoized` — cache a function by argument identity.
150
+ - `panic(message)` — throw immediately for unrecoverable states.
151
+ - `println` — dev logging, silent in production unless `setEnvironment` routes it.
152
+
153
+ ## Conventions agents should follow
154
+
155
+ - Named params in an object for multi-arg functions, not positional.
156
+ - No classes — use functions and plain objects.
157
+ - Error categories are strings (`.category`), not numeric codes. Never call them "error codes."
158
+ - `get` accepts a fallback; don't chain `.else()` after a `get` that already has one.
159
+ - `.panic()` throws — only for unrecoverable states. Use `Result` / `.else()` for expected failures.
160
+ - Zero runtime dependencies; ESM only.
161
+
162
+ ## Package contents
163
+
164
+ The published package ships `dist/` (JS + bundled declarations), `CHANGELOG.md`, and `skill/SKILL.md` (this file, for agents working with slang-ts).