slang-ts 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hussein Kizz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # Slang
2
+
3
+ Functional programming library for TypeScript.
4
+
5
+ My experiment to learn more functional programming and other cool programming stuff from other languages as I try to implement them in TypeScript.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm i slang-ts
11
+ ```
12
+
13
+ ## Implemented Utilities
14
+
15
+ - [x] Result (Ok, Err)
16
+ - [x] Maybe (Option)
17
+ - [ ] andThen
18
+ - [x] Atom
19
+ - [x] Expect
20
+ - [x] Unwrap (on Option)
21
+ - [x] Else (on unwrap)
22
+ - [ ] Panic!
23
+ - [x] Zip, Unzip, zipWith
24
+ - [ ] Try
25
+ - [ ] Catch
26
+ - [x] Match
27
+ - [x] MatchAll
28
+ - [ ] Pipe
29
+ - [ ] Map
30
+ - [x] To (converters, e.g. `userAtom.to('option')`)
31
+ - [ ] Promises and async utilities
32
+ - [ ] Curry
33
+
34
+ ## Others (Planned)
35
+
36
+ - Pubsub store with state locks
37
+
38
+ ## How It Works
39
+
40
+ You can import utilities individually or together:
41
+
42
+ ```ts
43
+ // Individual imports
44
+ import { option } from "slang-ts";
45
+ import { Ok, Err } from "slang-ts";
46
+
47
+ // Or import multiple at once
48
+ import { option, Ok, Err, atom, match } from "slang-ts";
49
+ ```
50
+
51
+ ### println
52
+
53
+ Well there's nothing special to slang's println utility, its just who wants console.log, its not fun at all, so we instead println, clean and classic, but latter it can be made environment aware so it doesn't print in prod, but for now its just sugar for console.log.
54
+
55
+ ```ts
56
+ import { println } from "slang-ts";
57
+
58
+ const name = "kizz";
59
+ println("name:", name);
60
+ println("multiple", "args", "work", { too: true });
61
+ ```
62
+
63
+ ### Option
64
+
65
+ Wraps values that may or may not be present. Returns `Some<T>` for truthy values, `None` for null, undefined, empty strings, NaN, or Infinity. Note that `0` and `false` are truthy as these are usually intentional.
66
+
67
+ ```ts
68
+ import { option } from "slang-ts";
69
+
70
+ const a = option("hi"); // Some("hi")
71
+ const b = option(null); // None
72
+ const c = option(0); // Some(0) - zero is truthy!
73
+ const d = option(""); // None
74
+ const e = option(false); // Some(false) - false is truthy!
75
+
76
+ if (a.isSome) {
77
+ println("Value:", a.value);
78
+ }
79
+
80
+ if (b.isNone) {
81
+ println("No value");
82
+ }
83
+ ```
84
+
85
+ ### Result
86
+
87
+ Represents operations that can succeed or fail. Returns `Ok<T>` on success or `Err<E>` on failure with typed error payload.
88
+
89
+ ```ts
90
+ import { Ok, Err, type Result } from "slang-ts";
91
+
92
+ // Simple function returning Result
93
+ function divide(a: number, b: number): Result<number, string> {
94
+ if (b === 0) return Err("Cannot divide by zero");
95
+ return Ok(a / b);
96
+ }
97
+
98
+ const result = divide(10, 2);
99
+
100
+ if (result.isOk) {
101
+ println("Success:", result.value); // 5
102
+ } else {
103
+ println("Error:", result.error);
104
+ }
105
+
106
+ // Async API example
107
+ interface User {
108
+ id: string;
109
+ name: string;
110
+ }
111
+
112
+ async function fetchUser(id: string): Promise<Result<User, string>> {
113
+ try {
114
+ const response = await fetch(`/api/users/${id}`);
115
+ if (!response.ok) return Err("User not found");
116
+ const user = await response.json();
117
+ return Ok(user);
118
+ } catch (error) {
119
+ return Err("Network error");
120
+ }
121
+ }
122
+
123
+ const user = await fetchUser("123");
124
+ if (user.isOk) {
125
+ println("User:", user.value.name);
126
+ }
127
+ ```
128
+
129
+ ### Atom
130
+
131
+ Creates unique, non-interned symbols with semantic descriptions. Each call produces a distinct identity. So ideally define them in one file and import from it everywhere else, great for env variables stuff.
132
+
133
+ ```ts
134
+ import { atom } from "slang-ts";
135
+
136
+ const userAtom = atom("kizz");
137
+ const user2Atom = atom("kizz");
138
+
139
+ println(userAtom === atom("kizz")); // false - non interned ✅
140
+ println(userAtom.description); // "kizz"
141
+
142
+ if (userAtom === user2Atom) {
143
+ println("all the same");
144
+ } else {
145
+ println("not the same"); // This prints!
146
+ }
147
+ ```
148
+
149
+ ### Match
150
+
151
+ Exhaustive pattern matching for `Option` and `Result` types. Forces you to handle all cases.
152
+
153
+ ```ts
154
+ import { match } from "slang-ts";
155
+
156
+ // Matching Results
157
+ const result = divide(10, 0);
158
+ match(result, {
159
+ Ok: (v) => println("Success:", v.value),
160
+ Err: (e) => println("Failed:", e.error),
161
+ });
162
+
163
+ // Matching Options
164
+ const maybePort = option(process.env.PORT);
165
+ match(maybePort, {
166
+ Some: (v) => println("Port:", v.value),
167
+ None: () => println("No port configured"),
168
+ });
169
+ ```
170
+
171
+ ### MatchAll
172
+
173
+ Pattern matching for primitives and atoms with required `_` fallback.
174
+
175
+ ```ts
176
+ import { matchAll } from "slang-ts";
177
+
178
+ // Match atoms
179
+ const ready = atom("ready");
180
+ matchAll(ready, {
181
+ ready: () => println("Ready!"),
182
+ failed: () => println("Failed!"),
183
+ _: () => println("Unknown"),
184
+ });
185
+
186
+ // Match booleans
187
+ const isActive = true;
188
+ matchAll(isActive, {
189
+ true: () => println("Active"),
190
+ false: () => println("Inactive"),
191
+ _: () => println("Unknown"),
192
+ });
193
+ ```
194
+
195
+ ### Expect
196
+
197
+ Unwraps values or throws with custom message. Use when failure is unrecoverable.
198
+
199
+ ```ts
200
+ const personAge = option(25).expect("a person must have age!");
201
+ println("person age", personAge); // 25
202
+
203
+ // This would throw!
204
+ // const personAge2 = option("").expect("a person must have age!");
205
+ ```
206
+
207
+ ### Unwrap/Else
208
+
209
+ Chainable unwrapping with mandatory fallback. Must call `.else()` or throws.
210
+
211
+ ```ts
212
+ const port = option(process.env.PORT).unwrap().else(3000);
213
+ println("Using port:", port);
214
+
215
+ // Function fallbacks
216
+ const retries = option(null).unwrap().else(() => 5);
217
+ println("Retries:", retries);
218
+
219
+ // This throws! No .else() chained
220
+ // const nothing = option(null).unwrap();
221
+ ```
222
+
223
+ ### To
224
+
225
+ Converts between Slang types.
226
+
227
+ ```ts
228
+ const statusAtom = atom("active").to("option");
229
+ println("Option:", statusAtom); // Some("active")
230
+
231
+ const stateOption = option("ready").to("atom");
232
+ println("Atom:", stateOption.description); // "ready"
233
+
234
+ const errResult = option(null).to("result");
235
+ println("Result:", errResult.type); // "Err"
236
+ ```
237
+
238
+ ### Zip
239
+
240
+ Combines multiple collections element-wise into tuples.
241
+
242
+ ```ts
243
+ import { zip } from "slang-ts";
244
+
245
+ // Zip arrays
246
+ const arr1 = [1, 2, 3];
247
+ const arr2 = [4, 5, 6];
248
+ const arr3 = [7, 8, 9];
249
+ println(zip([arr1, arr2, arr3]));
250
+ // [[1,4,7],[2,5,8],[3,6,9]]
251
+
252
+ // Zip with fillValue
253
+ println(zip([arr1, [10, 20]], { fillValue: 0 }));
254
+ // [[1,10],[2,20],[3,0]]
255
+
256
+ // Zip Sets with includeValues=true
257
+ const s1 = new Set([10, 20, 30]);
258
+ const s2 = new Set([100, 200, 300]);
259
+ println(zip([s1, s2], { includeValues: true }));
260
+ // [[10,100],[20,200],[30,300]]
261
+
262
+ // Zip objects with includeValues=true
263
+ const o1 = { a: 1, b: 2, c: 3 };
264
+ const o2 = { x: 100, y: 200, z: 300 };
265
+ println(zip([o1, o2], { includeValues: true }));
266
+ // [[1,100],[2,200],[3,300]]
267
+ ```
268
+
269
+ ### ZipWith
270
+
271
+ Combines collections and applies transform function to each tuple.
272
+
273
+ ```ts
274
+ import { zipWith } from "slang-ts";
275
+
276
+ const arr1 = [1, 2, 3];
277
+ const arr2 = [4, 5, 6];
278
+ const arr3 = [7, 8, 9];
279
+
280
+ println(zipWith([arr1, arr2, arr3], (t) => t.reduce((sum, x) => sum + x, 0)));
281
+ // [12, 15, 18]
282
+ ```
283
+
284
+ ### Unzip
285
+
286
+ Reverses zip operation, separating tuples back into arrays.
287
+
288
+ ```ts
289
+ import { unzip } from "slang-ts";
290
+
291
+ const arr1 = [1, 2, 3];
292
+ const arr2 = [4, 5, 6];
293
+
294
+ const zipped = zip([arr1, arr2]);
295
+ println(unzip(zipped));
296
+ // [[1, 2, 3], [4, 5, 6]]
297
+ ```
298
+
299
+ And more are to be implemented in coming versions...
300
+
301
+ ## Code Samples
302
+
303
+ See [example.ts](https://github.com/Hussseinkizz/slang/blob/main/example.ts) for usage of currently implemented methods.
304
+
305
+ ## Contributing
306
+
307
+ Contributions are welcome, I know there a lot of cool things out there we can bring in.
@@ -0,0 +1,281 @@
1
+ export declare const println: (...args: unknown[]) => void;
2
+ /**
3
+ * Converts between Slang types.
4
+ * - `option`: Wraps primitive or symbol description into `Option`
5
+ * - `atom`: Converts `Some<string>` to `Atom` or returns symbol Atom
6
+ * - `result`: Wraps values into `Ok`, `None` into `Err`
7
+ */
8
+ export declare function _to<T>(value: Option<T>, target: "option"): Option<T>;
9
+ export declare function _to<T extends string>(value: Option<T>, target: "atom"): Atom<T>;
10
+ export declare function _to<T extends string>(value: Atom<T>, target: "option"): Option<string>;
11
+ export declare function _to<T extends string>(value: Atom<T>, target: "atom"): Atom<T>;
12
+ export declare function _to<T, E = string>(value: Option<T>, target: "result"): Result<T, E>;
13
+ export declare function _to<E = string>(value: Atom<any>, target: "result"): Result<string, E>;
14
+ /** Unique symbol to brand atoms */
15
+ declare const __atom__: unique symbol;
16
+ /** Atom type carrying the original name for hover/type info */
17
+ export type Atom<T extends string = string> = symbol & {
18
+ readonly [__atom__]: T;
19
+ };
20
+ /**
21
+ * Creates a new, unique atom (non-interned)
22
+ * @param name Name of the atom (used for hover/description)
23
+ * @example
24
+ * const a = atom("loading");
25
+ * typeof a; // Atom<"loading">
26
+ */
27
+ /**
28
+ * Creates a new, unique atom (non-interned)
29
+ * @param name Name of the atom (used for hover/description)
30
+ * @returns `Atom<T>` with chainable `to()`
31
+ * @example
32
+ * const ready = atom("ready");
33
+ * ready.to("option"); // Some("ready")
34
+ * ready.to("result"); // Ok("ready")
35
+ */
36
+ /** Methods available on an Atom */
37
+ export interface AtomMethods<T extends string> {
38
+ /** Returns the same atom */
39
+ to(target: "atom"): Atom<T>;
40
+ /** Returns `Option<string>` using the atom description
41
+ * @example atom("ready").to("option") // Some("ready")
42
+ */
43
+ to(target: "option"): Option<string>;
44
+ /** Returns `Ok<string>` using the atom description
45
+ * @example atom("ready").to("result") // Ok("ready")
46
+ */
47
+ to(target: "result"): Result<string, string>;
48
+ }
49
+ export declare function atom<const T extends string>(name: T): Atom<T> & AtomMethods<T>;
50
+ declare const __result__: unique symbol;
51
+ export type Ok<T> = {
52
+ type: "Ok";
53
+ value: T;
54
+ readonly isOk: true;
55
+ readonly isErr: false;
56
+ readonly [__result__]: true;
57
+ };
58
+ export type Err<E> = {
59
+ type: "Err";
60
+ error: E;
61
+ readonly isOk: false;
62
+ readonly isErr: true;
63
+ readonly [__result__]: true;
64
+ };
65
+ export type Result<T, E> = (Ok<T> | Err<E>) & ResultMethods<T>;
66
+ /**
67
+ * Creates a new, successful result
68
+ * @param value Value of the result
69
+ * @example
70
+ * const a = Ok("hello");
71
+ * typeof a; // Ok<"hello">
72
+ */
73
+ /** Methods available on a Result */
74
+ export interface ResultMethods<T> {
75
+ /** Unwraps the value, throwing for Err
76
+ * @example maybeFail().expect("must succeed")
77
+ */
78
+ expect(msg?: string): T;
79
+ /** Returns an unwrap chain that throws if no else is provided
80
+ * Use `.else(valueOrFn)` to supply a fallback for Err.
81
+ * - If `Ok`, `.else(...)` returns the inner value and ignores fallback.
82
+ * - If `Err`, `.else(...)` returns the fallback; if a function, it receives the error.
83
+ */
84
+ unwrap(): {
85
+ /** Fallback value or function to recover from Err
86
+ * If a function is provided, it is called with the Err's error.
87
+ * Returns the unwrapped value (Ok) or the provided fallback (Err).
88
+ */ else(fallback: T | ((error: any) => T)): T;
89
+ };
90
+ }
91
+ /** Creates a new, successful result */
92
+ export declare function Ok<T>(value: T): Ok<T> & ResultMethods<T>;
93
+ /**
94
+ * Creates a new, failed result
95
+ * @param error Error of the result
96
+ * @example
97
+ * const a = Err("error");
98
+ * typeof a; // Err<"error">
99
+ */
100
+ /** Creates a new, failed result */
101
+ export declare function Err<E>(error: E): Err<E> & ResultMethods<never>;
102
+ declare const __option__: unique symbol;
103
+ export type Some<T> = {
104
+ type: "Some";
105
+ value: T;
106
+ readonly isSome: true;
107
+ readonly isNone: false;
108
+ readonly [__option__]: true;
109
+ };
110
+ export type None = {
111
+ type: "None";
112
+ readonly isSome: false;
113
+ readonly isNone: true;
114
+ readonly [__option__]: true;
115
+ };
116
+ export type Option<T> = (Some<T> | None) & OptionMethods<T>;
117
+ export type NonTruthy = null | undefined | "";
118
+ /**
119
+ * Creates a new option type from a value
120
+ * @param value - the value to be made an option
121
+ * @tutorial The returned option will be Some if the value is truthy, and None if it is not (null,undefined,Nan,'')
122
+ * @example
123
+ * const b = option("hello");
124
+ * typeof b; // Some<"hello">
125
+ * const c = option(null);
126
+ * typeof c; // None
127
+ * const d = option(undefined);
128
+ * typeof d; // None
129
+ * const e = option(0);
130
+ * typeof e; // Some<number>
131
+ * const f = option("");
132
+ * typeof f; // None
133
+ * const g = option(false);
134
+ * typeof g; // Some<boolean>
135
+ */
136
+ /** Methods available on an Option */
137
+ export interface OptionMethods<T> {
138
+ /** Returns the same option */
139
+ to(target: "option"): Option<T>;
140
+ /** Converts `Some<string>` to `Atom<string>`; throws for `None` or non-string */
141
+ to(target: "atom"): Atom<T & string>;
142
+ /** Converts to `Result<T, string>`; `None` becomes `Err("Value is None")` */
143
+ to(target: "result"): Result<T | (T extends string ? never : Atom<string>), string>;
144
+ /**
145
+ * Unwraps the option, throwing if `None`.
146
+ * @throws Error with provided message or default.
147
+ * @example
148
+ * option(42).expect(); // 42
149
+ * option("").expect("must be present"); // throws
150
+ */
151
+ expect(msg?: string): T;
152
+ /** Returns an unwrap chain that MUST be completed with `.else(...)`.
153
+ * If `.else(...)` is not chained, an error is thrown ("Expected else").
154
+ * - If `Some`, `.else(...)` is required but ignored for outcome; returns the inner value.
155
+ * - If `None`, `.else(...)` provides fallback; if a function, it is called with `undefined`.
156
+ * - Fallback result must be truthy; otherwise, throws ("Fallback must be truthy").
157
+ */
158
+ unwrap(): {
159
+ /** Fallback value or transformer to recover from `None`.
160
+ * - Function form receives `undefined` and must return a truthy value.
161
+ * - Direct value must be truthy.
162
+ * Returns the inner value for `Some`, or the validated fallback for `None`.
163
+ */ else(fallback: T | ((value: T | undefined) => T)): T;
164
+ };
165
+ }
166
+ /**
167
+ * Creates a new option type from a value.
168
+ * - Truthy values become `Some<T>`; `null|undefined|""` become `None`.
169
+ * - Provides chainable `.to()` and `.expect()` helpers.
170
+ * @example
171
+ * option("hi").expect(); // "hi"
172
+ * option("").expect("cannot be empty"); // throws Error("cannot be empty")
173
+ * option("state").to("atom"); // Atom<"state">
174
+ * option(null).to("result"); // Err("Value is None")
175
+ */
176
+ export declare function option<T>(value: T | NonTruthy): Option<T> & OptionMethods<T>;
177
+ /**
178
+ * Pattern matching for `Result` and `Option` — exhaustiveness enforced.
179
+ *
180
+ * Returns the value returned by the selected handler. If all handlers return
181
+ * `Result` or `Option`, TypeScript will infer that automatically.
182
+ */
183
+ export declare function match<T, E, R>(value: Result<T, E>, patterns: {
184
+ Ok: (v: Ok<T>) => R;
185
+ Err: (e: Err<E>) => R;
186
+ }): R;
187
+ export declare function match<T, R>(value: Option<T>, patterns: {
188
+ Some: (v: Some<T>) => R;
189
+ None: (v: None) => R;
190
+ }): R;
191
+ /**
192
+ * Allowed keys in matchAll patterns.
193
+ * - Strings, numbers, and Atom descriptions.
194
+ * - Booleans are represented as "true" | "false" strings
195
+ */
196
+ type MatchKey = string | number | symbol;
197
+ /**
198
+ * Type-safe pattern object: must always have `_` fallback.
199
+ */
200
+ type MatchPatterns<V, R> = {
201
+ [K in MatchKey]?: (v: V) => R;
202
+ } & {
203
+ _: () => R;
204
+ };
205
+ /**
206
+ * Matches a value against literal or Atom cases by *semantic name*.
207
+ * - Supports string, number, booleans and Atom (symbol) values.
208
+ * - Unsupported will throw an error. (objects, arrays, functions, etc)
209
+ * - For Atoms, uses their description as a key (e.g. atom("ready") → "ready").
210
+ * - Requires a `_` default handler.
211
+ *
212
+ * @example
213
+ * matchAll(ready, {
214
+ * 1: () => println("One"),
215
+ * 2: () => println("Two"),
216
+ * 0: () => println("Zero"),
217
+ * true: () => println("True"),
218
+ * false: () => println("False"),
219
+ * ready: () => println("Ready!"),
220
+ * failed: () => println("Failed!"),
221
+ * _: () => println("Unknown!"),
222
+ * });
223
+ */
224
+ export declare function matchAll<T extends MatchKey | boolean, R>(value: T, patterns: MatchPatterns<T, R>): R;
225
+ /**
226
+ * Combines multiple collections element-wise into tuples.
227
+ * - All inputs must be the same type (all arrays, all Sets, or all objects).
228
+ * - By default, only arrays are allowed; set `includeValues: true` to extract values from Sets/Objects.
229
+ * - Stops at shortest collection by default; use `fillValue` to extend to longest.
230
+ * - Transforms columns into rows for parallel iteration.
231
+ * @param inputs Collections of the same type to combine
232
+ * @param options Configuration: `fillValue` extends to longest, `includeValues` extracts values from Sets/Objects (default: false)
233
+ * @returns Array of tuples, one per index position
234
+ * @example
235
+ * zip([[1, 2], ['a', 'b']]); // [[1, 'a'], [2, 'b']]
236
+ * zip([[1, 2], ['a']], { fillValue: 'x' }); // [[1, 'a'], [2, 'x']]
237
+ * const s1 = new Set([1, 2]); const s2 = new Set([3, 4]);
238
+ * zip([s1, s2], { includeValues: true }); // [[1, 3], [2, 4]]
239
+ */
240
+ export declare function zip<T extends readonly any[]>(inputs: {
241
+ [K in keyof T]: Iterable<T[K]> | {
242
+ [key: string]: T[K];
243
+ };
244
+ }, options?: {
245
+ fillValue?: T[number];
246
+ includeValues?: boolean;
247
+ }): T[number][][];
248
+ /**
249
+ * Combines multiple collections element-wise and transforms each tuple.
250
+ * - All inputs must be the same type (all arrays, all Sets, or all objects).
251
+ * - By default, only arrays are allowed; set `includeValues: true` to extract values from Sets/Objects.
252
+ * - Applies a function to each set of corresponding elements.
253
+ * - Useful for aggregating, computing, or transforming aligned data.
254
+ * @param inputs Collections of the same type to combine
255
+ * @param fn Transform function applied to each tuple
256
+ * @param options Configuration: `fillValue` extends to longest, `includeValues` extracts values from Sets/Objects (default: false)
257
+ * @returns Array of transformed results
258
+ * @example
259
+ * zipWith([[1, 2], [3, 4]], (t) => t[0] + t[1]); // [4, 6]
260
+ * zipWith([[1, 2], [10]], (t) => t.reduce((a, b) => a + b, 0), { fillValue: 0 }); // [11, 2]
261
+ */
262
+ export declare function zipWith<T extends readonly any[], R>(inputs: {
263
+ [K in keyof T]: Iterable<T[K]> | {
264
+ [key: string]: T[K];
265
+ };
266
+ }, fn: (tuple: T[number][]) => R, options?: {
267
+ fillValue?: T[number];
268
+ includeValues?: boolean;
269
+ }): R[];
270
+ /**
271
+ * Unzips an array of tuples back into separate arrays.
272
+ * - Reverses the zip operation: transforms rows to columns.
273
+ * - Useful for separating previously combined collections.
274
+ * @param zipped Array of tuples (rows) to transpose
275
+ * @returns Array of arrays (columns), one per tuple position
276
+ * @example
277
+ * const zipped = [[1, 'a'], [2, 'b'], [3, 'c']];
278
+ * unzip(zipped); // [[1, 2, 3], ['a', 'b', 'c']]
279
+ */
280
+ export declare function unzip<T>(zipped: T[][]): T[][];
281
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ var _=(...j)=>{globalThis?.console?.log?.(...j)},Z=(j)=>{let B=globalThis?.queueMicrotask;if(typeof B==="function")B(j);else Promise.resolve().then(j)};function $(j,B){let G=(H)=>H!=null&&typeof H==="object"&&("isSome"in H)&&("isNone"in H);if(j&&(j.type==="Ok"||j.type==="Err"))throw Error("Cannot convert a Result to any other type");switch(B){case"option":{if(G(j))return j;if(typeof j==="symbol")return Y(j.description);return Y(j)}case"atom":{if(G(j)){if(j.isNone)throw Error("Cannot convert None to Atom");if(typeof j.value!=="string")throw Error("Only string values can be converted to Atom");return N(j.value)}if(typeof j==="symbol")return j;throw Error(`Cannot convert type ${typeof j} to Atom`)}case"result":{if(G(j))return j.isSome?X(j.value):R("Value is None");if(typeof j==="symbol")return X(j.description);return X(j)}default:throw Error(`Invalid target: ${B}`)}}function N(j){let B=Symbol(j),G=Object(B),H=(D)=>$(B,D);return G.to=H,G}function X(j){let B=Object.freeze({type:"Ok",value:j,isOk:!0,isErr:!1});return{...B,expect:(H)=>B.value,unwrap:()=>{let H=!1;return Z(()=>{}),{else(D){return H=!0,B.value}}}}}function R(j){let B=Object.freeze({type:"Err",error:j,isOk:!1,isErr:!0}),G=(D,I)=>{if(typeof D==="string")return D;if(D&&typeof D==="object"&&"message"in D)return String(D.message);return I??String(D)};return{...B,expect:(D)=>{throw Error(D??G(B.error,"Expected Ok, got Err"))},unwrap:()=>{let D=!1;return Z(()=>{if(!D){let I=G(B.error,"Expected Ok, got Err");throw Error(I)}}),{else(I){if(D=!0,typeof I==="function")return I(B.error);return I}}}}}var C=(j)=>{return j===null||j===void 0||j===""||Number.isNaN(j)||j===1/0||j===-1/0};function q(j){if(C(j))throw Error("Cannot wrap null, undefined, NaN, or empty string in Some");return Object.freeze({type:"Some",value:j,isSome:!0,isNone:!1})}var F=Object.freeze({type:"None",isSome:!1,isNone:!0});function Y(j){let B=C(j)?F:q(j);return{...B,to:(P)=>$(B,P),expect:(P)=>{if(B.isSome)return B.value;throw Error(P??"Expected Some, got None")},unwrap:()=>{let P=!1,Q=B;return Z(()=>{if(!P)throw Error("Expected else")}),{else(T){if(P=!0,Q.isSome)return Q.value;let J=typeof T==="function"?T(void 0):T;if(Y(J).isNone)throw Error("Fallback must be truthy");return J}}}}}function A(j,B){let G=B[j.type];if(!G)throw Error(`Non-exhaustive match — missing handler for '${j.type}'`);return G(j)}var L=(j)=>{return typeof j==="string"||typeof j==="number"||typeof j==="boolean"||typeof j==="symbol"};function E(j,B){let G=(Q)=>typeof Q?.valueOf==="function"?Q.valueOf():Q,H=(Q)=>typeof Q==="symbol"?Q.description:void 0,D=G(j);if(!L(D))throw Error(`Unsupported match all value type: ${typeof D}`);let I=H(D)??D,P=typeof I==="boolean"||typeof I==="number"?String(I):I;if(P!=null&&P in B)return B[P](j);return B._()}function S(j,B=!1){if(!B&&!Array.isArray(j))throw Error("Only arrays allowed when includeValues=false");if(Array.isArray(j))return j;if(j instanceof Set)return Array.from(j);return Object.values(j)}function U(j,B){let{fillValue:G,includeValues:H=!1}=B||{};if(j.length===0)return[];let D=j.map((J)=>S(J,H)),I=Math.max(...D.map((J)=>J.length)),P=Math.min(...D.map((J)=>J.length)),Q=G===void 0?P:I,T=[];for(let J=0;J<Q;J++)T.push(D.map((W)=>J<W.length?W[J]:G));return T}function K(j,B,G){return U(j,G).map(B)}function M(j){if(j.length===0)return[];let B=j[0]?.length??0,G=Array.from({length:B},()=>[]);for(let H of j)H.forEach((D,I)=>G[I]?.push(D));return G}export{K as zipWith,U as zip,M as unzip,_ as println,Y as option,E as matchAll,A as match,N as atom,$ as _to,X as Ok,R as Err};
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "slang-ts",
3
+ "version": "0.0.1",
4
+ "description": "Functional programming library for TypeScript",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "exports": {
9
+ ".": "./dist/index.js"
10
+ },
11
+ "types": "dist/index.d.ts",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "test:ui": "vitest --ui",
19
+ "typecheck": "tsc --noEmit",
20
+ "build": "bun run test && bun run typecheck && bun run bun-build.ts && tsc -p tsconfig.build.json"
21
+ },
22
+ "homepage": "https://github.com/Hussseinkizz/slang#readme",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/Hussseinkizz/slang.git"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/Hussseinkizz/slang/issues"
29
+ },
30
+ "keywords": [
31
+ "functional",
32
+ "typescript",
33
+ "option",
34
+ "result",
35
+ "pattern-matching",
36
+ "monad",
37
+ "ts-pattern",
38
+ "defensive programming",
39
+ "fp-ts",
40
+ "ramda",
41
+ "rameda",
42
+ "neverthrow",
43
+ "lodash"
44
+ ],
45
+ "author": "Hussein Kizz",
46
+ "license": "MIT",
47
+ "sideEffects": false,
48
+ "devDependencies": {
49
+ "@types/bun": "latest",
50
+ "@vitest/ui": "^4.0.15",
51
+ "vitest": "^4.0.15"
52
+ },
53
+ "peerDependencies": {
54
+ "typescript": "^5"
55
+ }
56
+ }