slang-ts 0.0.8 → 0.1.0

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
@@ -38,6 +38,16 @@ npm i slang-ts
38
38
 
39
39
  All utilities fully tested. See [tests](https://github.com/Hussseinkizz/slang/tree/main/tests)
40
40
 
41
+ ## New in v0.0.10
42
+
43
+ - **Ok messages**: `Ok(value, message?)` keeps an optional success message on the result, such as text to show the user. Results without one have no `message` property.
44
+
45
+ ## New in v0.0.9
46
+
47
+ - **SafeTry**: unwraps nested Result, Option, and Atom values into one result; nested failures now become the outer `Err`, while plain object properties and array elements stay unchanged.
48
+ - **Package types**: bundled declarations work with strict NodeNext consumers, so importing the package no longer exposes invalid declaration paths.
49
+ - **Build tooling**: tsdown and TypeScript 7 build JavaScript and bundled types together.
50
+
41
51
  ## New in v0.0.8
42
52
 
43
53
  - **Signal**: a simple on/off trigger that fires once and stays fired; use it to make something start only after something else finishes.
@@ -128,8 +138,16 @@ const user = await fetchUser("123");
128
138
  if (user.isOk) {
129
139
  println("User:", user.value.name);
130
140
  }
141
+
142
+ // Optional success message as the second argument
143
+ const saved = Ok({ id: "123" }, "Profile saved");
144
+ if (saved.isOk) {
145
+ println(saved.message); // "Profile saved"
146
+ }
131
147
  ```
132
148
 
149
+ `andThen` and `safeTry` return new results, so a message stays with the value it described.
150
+
133
151
  ### Expect
134
152
 
135
153
  Unwraps values or throws with custom message. Use when failure is unrecoverable.
@@ -283,36 +301,59 @@ Useful when values come from different functions with inconsistent return types
283
301
 
284
302
  ### SafeTry
285
303
 
286
- Wraps potentially throwing functions in try-catch, returning a `Result<T, string>`. Always needs to be awaited as its async.
304
+ Runs sync or async functions and captures failures as `Err<string>`. Always await it. Nested Result, Option, and Atom values resolve to one `Result`: `Ok` and `Some` unwrap until a plain value appears, `Err` stops with its error normalized through `String`, `None` becomes `Err("Option was None")`, and Atom becomes its description.
287
305
 
288
306
  ```ts
289
- import { safeTry } from "slang-ts";
307
+ import { safeTry, Ok, Err, option, atom, println, type Result } from "slang-ts";
290
308
 
291
- const result = await safeTry(() => {
292
- if (denom === 0) throw new Error("Cannot divide by zero");
293
- return num / denom;
294
- });
309
+ // Inferred type is Promise<Result<number, string>>, not nested Results.
310
+ const pending: Promise<Result<number, string>> = safeTry(() => Ok(Ok(42)));
311
+ const nested = await pending; // Ok(42)
312
+ if (nested.isOk) println(nested.value); // 42
295
313
 
296
- if (result.isOk) {
297
- println("Result:", result.value);
298
- } else {
299
- println("Error:", result.error);
300
- }
314
+ const failed = await safeTry(() => Ok(Ok(Err("Not found")))); // Err("Not found")
315
+ if (failed.isErr) println(failed.error); // "Not found"
301
316
 
302
- // Async functions work the same way
303
- const data = await safeTry(async () => {
304
- const res = await fetch("/api/user");
305
- return res.json();
306
- });
317
+ const mixed = await safeTry(() => Ok(option(Ok(atom("ready")))));
318
+ // Ok("ready"); inferred success value is the literal "ready".
319
+ if (mixed.isOk) println(mixed.value); // "ready"
307
320
 
308
- if (data.isOk) {
309
- println("User:", data.value);
310
- }
321
+ const missing = await safeTry(() => Ok(option(null))); // Err("Option was None")
322
+ if (missing.isErr) println(missing.error);
323
+
324
+ const caught = await safeTry(async () => {
325
+ throw new Error("Could not load profile");
326
+ }); // Err("Could not load profile")
327
+ if (caught.isErr) println(caught.error);
328
+ ```
329
+
330
+ Only the returned wrapper chain unwraps. Plain object properties and array elements stay as supplied. Only the callback's return is awaited; a Promise inside `Ok` or `Some` stays a Promise.
331
+
332
+ ```ts
333
+ import { safeTry, Ok, println } from "slang-ts";
334
+
335
+ const payload = { result: Ok(42), items: [Ok(7)] };
336
+ const plain = await safeTry(() => payload); // Ok(payload), same object
337
+ if (plain.isOk) println(plain.value === payload); // true
338
+
339
+ const innerPromise = Promise.resolve(42);
340
+ const wrapped = await safeTry(() => Ok(innerPromise));
341
+ // Ok(innerPromise), success value stays Promise<number>.
342
+ if (wrapped.isOk) println(wrapped.value === innerPromise); // true
343
+ ```
344
+
345
+ `{ throw: true }` rethrows errors caught while running the callback or reading its returned wrappers. Returned `Err` values still return normally. A circular wrapper chain returns `Err("Cannot resolve a circular value")`, including with `{ throw: true }`.
346
+
347
+ ```ts
348
+ import { safeTry, Ok, Err, println } from "slang-ts";
349
+
350
+ const returned = await safeTry(() => Ok(Err("Not found")), { throw: true });
351
+ if (returned.isErr) println(returned.error); // "Not found"
311
352
 
312
- // Re-throw critical errors instead of capturing
313
353
  await safeTry(() => {
314
- throw new Error("Critical!");
315
- }, { throw: true });
354
+ throw new Error("Critical failure");
355
+ }, { throw: true }).catch((error: Error) => println(error.message));
356
+ // "Critical failure": the call rejects instead of returning Err.
316
357
  ```
317
358
 
318
359
  ### Pipe
@@ -641,6 +682,21 @@ channel.when({
641
682
 
642
683
  See [example.ts](https://github.com/Hussseinkizz/slang/blob/main/example.ts) for usage of currently implemented methods.
643
684
 
685
+ ## Development
686
+
687
+ Install project dependencies with Bun, then build:
688
+
689
+ ```bash
690
+ bun install
691
+ bun run build
692
+ ```
693
+
694
+ The build runs tests, checks types with TypeScript 7.0.2, then uses tsdown 0.23.1 to produce minified ESM at `dist/index.js` and bundled types at `dist/index.d.ts`. Package imports keep the same entry points. tsdown currently marks its TypeScript 7 integration as experimental; the project build passes with this setup.
695
+
696
+ For building, tsdown requires Node.js `^22.18.0 || ^24.11.0 || >=26.0.0`. This is a build-tool requirement, not a new runtime requirement for Slang consumers.
697
+
698
+ Packaged output passes strict consumer checks with TypeScript 5.9.3 and 7.0.2 under both NodeNext and Bundler resolution, including declaration checking. See [migration context](context.md) for verification details.
699
+
644
700
  ## Contributing
645
701
 
646
702
  Contributions are welcome. I know there are a lot of cool things out there we can bring in.