@nunofyobiz/effect-extras 2.0.0 → 3.0.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 +38 -3
- package/dist/ArrayX.d.ts +381 -0
- package/dist/ArrayX.d.ts.map +1 -0
- package/dist/ArrayX.js +493 -0
- package/dist/ArrayX.js.map +1 -0
- package/dist/BigIntX.d.ts +24 -0
- package/dist/BigIntX.d.ts.map +1 -0
- package/dist/BigIntX.js +30 -0
- package/dist/BigIntX.js.map +1 -0
- package/dist/BooleanX.d.ts +25 -0
- package/dist/BooleanX.d.ts.map +1 -0
- package/dist/BooleanX.js +25 -0
- package/dist/BooleanX.js.map +1 -0
- package/dist/DurationX.d.ts +73 -0
- package/dist/DurationX.d.ts.map +1 -0
- package/dist/DurationX.js +91 -0
- package/dist/DurationX.js.map +1 -0
- package/dist/EffectX.d.ts +120 -0
- package/dist/EffectX.d.ts.map +1 -0
- package/dist/EffectX.js +140 -0
- package/dist/EffectX.js.map +1 -0
- package/dist/FormDataX.d.ts +49 -0
- package/dist/FormDataX.d.ts.map +1 -0
- package/dist/FormDataX.js +42 -0
- package/dist/FormDataX.js.map +1 -0
- package/dist/InclusiveOr.d.ts +1123 -0
- package/dist/InclusiveOr.d.ts.map +1 -0
- package/dist/InclusiveOr.js +1074 -0
- package/dist/InclusiveOr.js.map +1 -0
- package/dist/MapX.d.ts +32 -0
- package/dist/MapX.d.ts.map +1 -0
- package/dist/MapX.js +49 -0
- package/dist/MapX.js.map +1 -0
- package/dist/NonNullableX.d.ts +174 -0
- package/dist/NonNullableX.d.ts.map +1 -0
- package/dist/NonNullableX.js +217 -0
- package/dist/NonNullableX.js.map +1 -0
- package/dist/NumberX.d.ts +178 -0
- package/dist/NumberX.d.ts.map +1 -0
- package/dist/NumberX.js +214 -0
- package/dist/NumberX.js.map +1 -0
- package/dist/OptionX.d.ts +187 -0
- package/dist/OptionX.d.ts.map +1 -0
- package/dist/OptionX.js +201 -0
- package/dist/OptionX.js.map +1 -0
- package/dist/OrderX.d.ts +32 -0
- package/dist/OrderX.d.ts.map +1 -0
- package/dist/OrderX.js +32 -0
- package/dist/OrderX.js.map +1 -0
- package/dist/PredicateX.d.ts +108 -0
- package/dist/PredicateX.d.ts.map +1 -0
- package/dist/PredicateX.js +111 -0
- package/dist/PredicateX.js.map +1 -0
- package/dist/PromiseX.d.ts +32 -0
- package/dist/PromiseX.d.ts.map +1 -0
- package/dist/PromiseX.js +32 -0
- package/dist/PromiseX.js.map +1 -0
- package/dist/RecordX.d.ts +450 -0
- package/dist/RecordX.d.ts.map +1 -0
- package/dist/RecordX.js +487 -0
- package/dist/RecordX.js.map +1 -0
- package/dist/ResultX.d.ts +50 -0
- package/dist/ResultX.d.ts.map +1 -0
- package/dist/ResultX.js +50 -0
- package/dist/ResultX.js.map +1 -0
- package/dist/SchemaX.d.ts +249 -0
- package/dist/SchemaX.d.ts.map +1 -0
- package/dist/SchemaX.js +243 -0
- package/dist/SchemaX.js.map +1 -0
- package/dist/SetX.d.ts +121 -0
- package/dist/SetX.d.ts.map +1 -0
- package/dist/SetX.js +137 -0
- package/dist/SetX.js.map +1 -0
- package/dist/StringX.d.ts +131 -0
- package/dist/StringX.d.ts.map +1 -0
- package/dist/StringX.js +149 -0
- package/dist/StringX.js.map +1 -0
- package/dist/StructX.d.ts +219 -0
- package/dist/StructX.d.ts.map +1 -0
- package/dist/StructX.js +173 -0
- package/dist/StructX.js.map +1 -0
- package/dist/WarnResult.d.ts +1191 -0
- package/dist/WarnResult.d.ts.map +1 -0
- package/dist/WarnResult.js +991 -0
- package/dist/WarnResult.js.map +1 -0
- package/dist/index.d.ts +23 -3772
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -1011
- package/dist/index.js.map +1 -1
- package/package.json +18 -5
- package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +6 -88
- package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
- package/src/InclusiveOr.ts +1255 -0
- package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +5 -0
- package/src/{OptionX/OptionX.ts → OptionX.ts} +8 -2
- package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +41 -0
- package/src/{RecordX/RecordX.ts → RecordX.ts} +184 -2
- package/src/StringX.ts +210 -0
- package/src/{WarnResult/WarnResult.ts → WarnResult.ts} +297 -227
- package/src/index.ts +22 -20
- package/src/ArrayX/index.ts +0 -1
- package/src/BigIntX/index.ts +0 -1
- package/src/BooleanX/index.ts +0 -1
- package/src/DurationX/index.ts +0 -1
- package/src/EffectX/index.ts +0 -1
- package/src/FormDataX/index.ts +0 -1
- package/src/MapX/index.ts +0 -1
- package/src/NonNullableX/index.ts +0 -2
- package/src/NumberX/index.ts +0 -1
- package/src/OptionX/index.ts +0 -1
- package/src/OrderX/index.ts +0 -1
- package/src/PredicateX/index.ts +0 -1
- package/src/PromiseX/index.ts +0 -1
- package/src/RecordX/index.ts +0 -1
- package/src/ResultX/index.ts +0 -1
- package/src/SchemaX/index.ts +0 -1
- package/src/SetX/index.ts +0 -1
- package/src/StringX/StringX.ts +0 -97
- package/src/StringX/index.ts +0 -1
- package/src/StructX/index.ts +0 -1
- package/src/WarnResult/index.ts +0 -1
- /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
- /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
- /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
- /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
- /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
- /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
- /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
- /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
- /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
- /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
- /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
- /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
package/dist/SetX.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions for working with `Set`.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { dual } from "effect/Function";
|
|
7
|
+
/**
|
|
8
|
+
* Runs a mutating function against a copy of `set`, leaving the original
|
|
9
|
+
* untouched, and returns the mutated copy.
|
|
10
|
+
*
|
|
11
|
+
* Use it to reuse imperative `Set` mutation code (`.add`, `.delete`) without
|
|
12
|
+
* sacrificing immutability: the callback may freely mutate the set it receives
|
|
13
|
+
* because it operates on a fresh clone. Supports both data-first and data-last
|
|
14
|
+
* (pipeable) call styles.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { SetX } from "@nunofyobiz/effect-extras"
|
|
19
|
+
* import { pipe } from "effect"
|
|
20
|
+
*
|
|
21
|
+
* const original = new Set(["a", "b"])
|
|
22
|
+
*
|
|
23
|
+
* const result = pipe(
|
|
24
|
+
* original,
|
|
25
|
+
* SetX.safelyMutate((set) => {
|
|
26
|
+
* set.delete("a")
|
|
27
|
+
* return set.add("c")
|
|
28
|
+
* })
|
|
29
|
+
* )
|
|
30
|
+
*
|
|
31
|
+
* assert.deepStrictEqual(result, new Set(["b", "c"]))
|
|
32
|
+
* // The original is left intact
|
|
33
|
+
* assert.deepStrictEqual(original, new Set(["a", "b"]))
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @category combinators
|
|
37
|
+
* @since 0.0.0
|
|
38
|
+
*/
|
|
39
|
+
export const safelyMutate = /*#__PURE__*/dual(2, (set, mutate) => {
|
|
40
|
+
const copy = new Set(set);
|
|
41
|
+
return mutate(copy);
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* Returns a new `Set` with `value` added, leaving the input set unchanged.
|
|
45
|
+
*
|
|
46
|
+
* When `value` is already present the input set is returned as-is (no copy),
|
|
47
|
+
* making repeated adds of existing members allocation-free. Supports both
|
|
48
|
+
* data-first and data-last (pipeable) call styles.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { SetX } from "@nunofyobiz/effect-extras"
|
|
53
|
+
* import { pipe } from "effect"
|
|
54
|
+
*
|
|
55
|
+
* // Data-first — adds a new element into a fresh set
|
|
56
|
+
* assert.deepStrictEqual(
|
|
57
|
+
* SetX.add(new Set(["a", "b"]), "c"),
|
|
58
|
+
* new Set(["a", "b", "c"])
|
|
59
|
+
* )
|
|
60
|
+
*
|
|
61
|
+
* // Data-last — existing element leaves the set unchanged
|
|
62
|
+
* assert.deepStrictEqual(
|
|
63
|
+
* pipe(new Set(["a", "b"]), SetX.add("b")),
|
|
64
|
+
* new Set(["a", "b"])
|
|
65
|
+
* )
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @category combinators
|
|
69
|
+
* @since 0.0.0
|
|
70
|
+
*/
|
|
71
|
+
export const add = /*#__PURE__*/dual(2, (set, value) => set.has(value) ? set : new Set(set).add(value));
|
|
72
|
+
/**
|
|
73
|
+
* Returns a new `Set` with `value` removed, leaving the input set unchanged.
|
|
74
|
+
*
|
|
75
|
+
* When `value` is absent the input set is returned as-is (no copy). Supports both
|
|
76
|
+
* data-first and data-last (pipeable) call styles.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { SetX } from "@nunofyobiz/effect-extras"
|
|
81
|
+
* import { pipe } from "effect"
|
|
82
|
+
*
|
|
83
|
+
* // Data-first — removes an existing element into a fresh set
|
|
84
|
+
* assert.deepStrictEqual(
|
|
85
|
+
* SetX.remove(new Set(["a", "b", "c"]), "c"),
|
|
86
|
+
* new Set(["a", "b"])
|
|
87
|
+
* )
|
|
88
|
+
*
|
|
89
|
+
* // Data-last — absent element leaves the set unchanged
|
|
90
|
+
* assert.deepStrictEqual(
|
|
91
|
+
* pipe(new Set(["a", "b"]), SetX.remove("z")),
|
|
92
|
+
* new Set(["a", "b"])
|
|
93
|
+
* )
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @category combinators
|
|
97
|
+
* @since 0.0.0
|
|
98
|
+
*/
|
|
99
|
+
export const remove = /*#__PURE__*/dual(2, (set, value) => {
|
|
100
|
+
if (set.has(value)) {
|
|
101
|
+
const newSet = new Set(set);
|
|
102
|
+
newSet.delete(value);
|
|
103
|
+
return newSet;
|
|
104
|
+
}
|
|
105
|
+
return set;
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* Returns a new `Set` with `value` added if it was absent or removed if it was
|
|
109
|
+
* present, leaving the input set unchanged.
|
|
110
|
+
*
|
|
111
|
+
* Use it for membership toggles (selection state, feature flags by key) where a
|
|
112
|
+
* value's presence should flip on each call. Supports both data-first and
|
|
113
|
+
* data-last (pipeable) call styles.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* import { SetX } from "@nunofyobiz/effect-extras"
|
|
118
|
+
* import { pipe } from "effect"
|
|
119
|
+
*
|
|
120
|
+
* // Data-first — absent value gets added
|
|
121
|
+
* assert.deepStrictEqual(
|
|
122
|
+
* SetX.toggle(new Set(["a", "b"]), "c"),
|
|
123
|
+
* new Set(["a", "b", "c"])
|
|
124
|
+
* )
|
|
125
|
+
*
|
|
126
|
+
* // Data-last — present value gets removed
|
|
127
|
+
* assert.deepStrictEqual(
|
|
128
|
+
* pipe(new Set(["a", "b", "c"]), SetX.toggle("b")),
|
|
129
|
+
* new Set(["a", "c"])
|
|
130
|
+
* )
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @category combinators
|
|
134
|
+
* @since 0.0.0
|
|
135
|
+
*/
|
|
136
|
+
export const toggle = /*#__PURE__*/dual(2, (set, value) => set.has(value) ? remove(set, value) : add(set, value));
|
|
137
|
+
//# sourceMappingURL=SetX.js.map
|
package/dist/SetX.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SetX.js","names":["dual","safelyMutate","set","mutate","copy","Set","add","value","has","remove","newSet","delete","toggle"],"sources":["../src/SetX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,IAAI,QAAQ,iBAAiB;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,OAAO,MAAMC,YAAY,gBAAGD,IAAI,CAG9B,CAAC,EAAE,CAAIE,GAAW,EAAEC,MAA+B,KAAY;EAC/D,MAAMC,IAAI,GAAG,IAAIC,GAAG,CAACH,GAAG,CAAC;EACzB,OAAOC,MAAM,CAACC,IAAI,CAAC;AACrB,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,OAAO,MAAME,GAAG,gBAAGN,IAAI,CAIrB,CAAC,EACD,CAAIE,GAAW,EAAEK,KAAQ,KACvBL,GAAG,CAACM,GAAG,CAACD,KAAK,CAAC,GAAGL,GAAG,GAAG,IAAIG,GAAG,CAACH,GAAG,CAAC,CAACI,GAAG,CAACC,KAAK,CAAC,CACjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,OAAO,MAAME,MAAM,gBAAGT,IAAI,CAGxB,CAAC,EAAE,CAAIE,GAAW,EAAEK,KAAQ,KAAY;EACxC,IAAIL,GAAG,CAACM,GAAG,CAACD,KAAK,CAAC,EAAE;IAClB,MAAMG,MAAM,GAAG,IAAIL,GAAG,CAACH,GAAG,CAAC;IAC3BQ,MAAM,CAACC,MAAM,CAACJ,KAAK,CAAC;IACpB,OAAOG,MAAM;EACf;EACA,OAAOR,GAAG;AACZ,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,OAAO,MAAMU,MAAM,gBAAGZ,IAAI,CAIxB,CAAC,EACD,CAAIE,GAAW,EAAEK,KAAQ,KACvBL,GAAG,CAACM,GAAG,CAACD,KAAK,CAAC,GAAGE,MAAM,CAACP,GAAG,EAAEK,KAAK,CAAC,GAAGD,GAAG,CAACJ,GAAG,EAAEK,KAAK,CAAC,CACxD","ignoreList":[]}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepends `start` to `string_`.
|
|
3
|
+
*
|
|
4
|
+
* v4's `String` module has no native `prepend` (only `concat`), so this fills
|
|
5
|
+
* the gap as a pipeable helper.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { pipe } from "effect"
|
|
10
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
11
|
+
*
|
|
12
|
+
* // data-first
|
|
13
|
+
* assert.deepStrictEqual(StringX.prepend("world", "hello "), "hello world")
|
|
14
|
+
*
|
|
15
|
+
* // data-last (piped)
|
|
16
|
+
* assert.deepStrictEqual(pipe("world", StringX.prepend("hello ")), "hello world")
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @category combinators
|
|
20
|
+
* @since 0.0.0
|
|
21
|
+
*/
|
|
22
|
+
export declare const prepend: ((start: string) => (string_: string) => string) & ((string_: string, start: string) => string);
|
|
23
|
+
/**
|
|
24
|
+
* Wraps `string_` between `start` and `end`.
|
|
25
|
+
*
|
|
26
|
+
* No v4 native equivalent — handy for quoting, bracketing, or fencing a value.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { pipe } from "effect"
|
|
31
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
32
|
+
*
|
|
33
|
+
* // data-first
|
|
34
|
+
* assert.deepStrictEqual(StringX.surround("value", "[", "]"), "[value]")
|
|
35
|
+
*
|
|
36
|
+
* // data-last (piped)
|
|
37
|
+
* assert.deepStrictEqual(pipe("value", StringX.surround("(", ")")), "(value)")
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @category combinators
|
|
41
|
+
* @since 0.0.0
|
|
42
|
+
*/
|
|
43
|
+
export declare const surround: ((start: string, end: string) => (string_: string) => string) & ((string_: string, start: string, end: string) => string);
|
|
44
|
+
/**
|
|
45
|
+
* Prepends `start` to `string_` unless `string_` already starts with it.
|
|
46
|
+
*
|
|
47
|
+
* Idempotent: applying it to an already-prefixed string is a no-op, so
|
|
48
|
+
* `ensurePrepend("foofoo", "foo")` stays `"foofoo"` rather than gaining a
|
|
49
|
+
* second `"foo"`.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { pipe } from "effect"
|
|
54
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
55
|
+
*
|
|
56
|
+
* // data-first — adds the prefix when missing
|
|
57
|
+
* assert.deepStrictEqual(StringX.ensurePrepend("bar", "foo"), "foobar")
|
|
58
|
+
*
|
|
59
|
+
* // idempotent — already prefixed, returned unchanged
|
|
60
|
+
* assert.deepStrictEqual(StringX.ensurePrepend("foobar", "foo"), "foobar")
|
|
61
|
+
*
|
|
62
|
+
* // data-last (piped)
|
|
63
|
+
* assert.deepStrictEqual(pipe("bar", StringX.ensurePrepend("foo")), "foobar")
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @category combinators
|
|
67
|
+
* @since 0.0.0
|
|
68
|
+
*/
|
|
69
|
+
export declare const ensurePrepend: ((start: string) => (string_: string) => string) & ((string_: string, start: string) => string);
|
|
70
|
+
/**
|
|
71
|
+
* Replaces the inclusive line range `[startLine, endLine]` of `content` with
|
|
72
|
+
* `replacement` lines, returning the rejoined string.
|
|
73
|
+
*
|
|
74
|
+
* `content` is split on `\n`; the zero-based lines `startLine` through `endLine`
|
|
75
|
+
* (both inclusive) are dropped and `replacement` is spliced into their place.
|
|
76
|
+
* Pass an empty `replacement` to delete the range. Indices clamp naturally via
|
|
77
|
+
* `Array.take`/`Array.drop`, so out-of-range values don't throw.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { pipe } from "effect"
|
|
82
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
83
|
+
*
|
|
84
|
+
* // data-first — replace lines 1..2 with a single line
|
|
85
|
+
* assert.deepStrictEqual(
|
|
86
|
+
* StringX.replaceLineRange("a\nb\nc\nd", 1, 2, ["X"]),
|
|
87
|
+
* "a\nX\nd",
|
|
88
|
+
* )
|
|
89
|
+
*
|
|
90
|
+
* // an empty replacement deletes the range
|
|
91
|
+
* assert.deepStrictEqual(StringX.replaceLineRange("a\nb\nc\nd", 1, 2, []), "a\nd")
|
|
92
|
+
*
|
|
93
|
+
* // data-last (piped)
|
|
94
|
+
* assert.deepStrictEqual(
|
|
95
|
+
* pipe("a\nb\nc", StringX.replaceLineRange(1, 1, ["X", "Y"])),
|
|
96
|
+
* "a\nX\nY\nc",
|
|
97
|
+
* )
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @category combinators
|
|
101
|
+
* @since 0.0.0
|
|
102
|
+
*/
|
|
103
|
+
export declare const replaceLineRange: ((startLine: number, endLine: number, replacement: readonly string[]) => (content: string) => string) & ((content: string, startLine: number, endLine: number, replacement: readonly string[]) => string);
|
|
104
|
+
/**
|
|
105
|
+
* Inserts `lines` immediately before the line at `anchorIndex`, preserving the
|
|
106
|
+
* anchor line and everything after it; returns the rejoined string.
|
|
107
|
+
*
|
|
108
|
+
* `content` is split on `\n` and `lines` are spliced in just before the
|
|
109
|
+
* zero-based `anchorIndex`. An `anchorIndex` of `0` prepends, and one at or past
|
|
110
|
+
* the end appends.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* import { pipe } from "effect"
|
|
115
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
116
|
+
*
|
|
117
|
+
* // data-first — insert before line 1, keeping the anchor and the rest
|
|
118
|
+
* assert.deepStrictEqual(StringX.insertBeforeLine("a\nb\nc", 1, ["X"]), "a\nX\nb\nc")
|
|
119
|
+
*
|
|
120
|
+
* // an anchor at the end appends
|
|
121
|
+
* assert.deepStrictEqual(StringX.insertBeforeLine("a\nb", 2, ["X"]), "a\nb\nX")
|
|
122
|
+
*
|
|
123
|
+
* // data-last (piped)
|
|
124
|
+
* assert.deepStrictEqual(pipe("a\nb", StringX.insertBeforeLine(0, ["X"])), "X\na\nb")
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @category combinators
|
|
128
|
+
* @since 0.0.0
|
|
129
|
+
*/
|
|
130
|
+
export declare const insertBeforeLine: ((anchorIndex: number, lines: readonly string[]) => (content: string) => string) & ((content: string, anchorIndex: number, lines: readonly string[]) => string);
|
|
131
|
+
//# sourceMappingURL=StringX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StringX.d.ts","sourceRoot":"","sources":["../src/StringX.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,OAAO,WACV,MAAM,KAAK,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,eACpC,MAAM,SAAS,MAAM,KAAK,MAAM,CAC0B,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,QAAQ,WACX,MAAM,OAAO,MAAM,KAAK,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,eACjD,MAAM,SAAS,MAAM,OAAO,MAAM,KAAK,MAAM,CAKxD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,aAAa,WAChB,MAAM,KAAK,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,eACpC,MAAM,SAAS,MAAM,KAAK,MAAM,CAO1C,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,gBAAgB,eAEd,MAAM,WACR,MAAM,eACF,SAAS,MAAM,EAAE,KAC3B,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,eAErB,MAAM,aACJ,MAAM,WACR,MAAM,eACF,SAAS,MAAM,EAAE,KAC3B,MAAM,CAmBZ,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,gBAAgB,iBAEZ,MAAM,SACZ,SAAS,MAAM,EAAE,KACrB,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,eACtB,MAAM,eAAe,MAAM,SAAS,SAAS,MAAM,EAAE,KAAK,MAAM,CAc3E,CAAC"}
|
package/dist/StringX.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions to Effect's `String` module.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Array } from "effect";
|
|
7
|
+
import { dual } from "effect/Function";
|
|
8
|
+
/**
|
|
9
|
+
* Prepends `start` to `string_`.
|
|
10
|
+
*
|
|
11
|
+
* v4's `String` module has no native `prepend` (only `concat`), so this fills
|
|
12
|
+
* the gap as a pipeable helper.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { pipe } from "effect"
|
|
17
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
18
|
+
*
|
|
19
|
+
* // data-first
|
|
20
|
+
* assert.deepStrictEqual(StringX.prepend("world", "hello "), "hello world")
|
|
21
|
+
*
|
|
22
|
+
* // data-last (piped)
|
|
23
|
+
* assert.deepStrictEqual(pipe("world", StringX.prepend("hello ")), "hello world")
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @category combinators
|
|
27
|
+
* @since 0.0.0
|
|
28
|
+
*/
|
|
29
|
+
export const prepend = /*#__PURE__*/dual(2, (string_, start) => `${start}${string_}`);
|
|
30
|
+
/**
|
|
31
|
+
* Wraps `string_` between `start` and `end`.
|
|
32
|
+
*
|
|
33
|
+
* No v4 native equivalent — handy for quoting, bracketing, or fencing a value.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { pipe } from "effect"
|
|
38
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
39
|
+
*
|
|
40
|
+
* // data-first
|
|
41
|
+
* assert.deepStrictEqual(StringX.surround("value", "[", "]"), "[value]")
|
|
42
|
+
*
|
|
43
|
+
* // data-last (piped)
|
|
44
|
+
* assert.deepStrictEqual(pipe("value", StringX.surround("(", ")")), "(value)")
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @category combinators
|
|
48
|
+
* @since 0.0.0
|
|
49
|
+
*/
|
|
50
|
+
export const surround = /*#__PURE__*/dual(3, (string_, start, end) => `${start}${string_}${end}`);
|
|
51
|
+
/**
|
|
52
|
+
* Prepends `start` to `string_` unless `string_` already starts with it.
|
|
53
|
+
*
|
|
54
|
+
* Idempotent: applying it to an already-prefixed string is a no-op, so
|
|
55
|
+
* `ensurePrepend("foofoo", "foo")` stays `"foofoo"` rather than gaining a
|
|
56
|
+
* second `"foo"`.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { pipe } from "effect"
|
|
61
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
62
|
+
*
|
|
63
|
+
* // data-first — adds the prefix when missing
|
|
64
|
+
* assert.deepStrictEqual(StringX.ensurePrepend("bar", "foo"), "foobar")
|
|
65
|
+
*
|
|
66
|
+
* // idempotent — already prefixed, returned unchanged
|
|
67
|
+
* assert.deepStrictEqual(StringX.ensurePrepend("foobar", "foo"), "foobar")
|
|
68
|
+
*
|
|
69
|
+
* // data-last (piped)
|
|
70
|
+
* assert.deepStrictEqual(pipe("bar", StringX.ensurePrepend("foo")), "foobar")
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @category combinators
|
|
74
|
+
* @since 0.0.0
|
|
75
|
+
*/
|
|
76
|
+
export const ensurePrepend = /*#__PURE__*/dual(2, (string_, start) => {
|
|
77
|
+
if (string_.startsWith(start)) {
|
|
78
|
+
return string_;
|
|
79
|
+
}
|
|
80
|
+
return `${start}${string_}`;
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* Replaces the inclusive line range `[startLine, endLine]` of `content` with
|
|
84
|
+
* `replacement` lines, returning the rejoined string.
|
|
85
|
+
*
|
|
86
|
+
* `content` is split on `\n`; the zero-based lines `startLine` through `endLine`
|
|
87
|
+
* (both inclusive) are dropped and `replacement` is spliced into their place.
|
|
88
|
+
* Pass an empty `replacement` to delete the range. Indices clamp naturally via
|
|
89
|
+
* `Array.take`/`Array.drop`, so out-of-range values don't throw.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { pipe } from "effect"
|
|
94
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
95
|
+
*
|
|
96
|
+
* // data-first — replace lines 1..2 with a single line
|
|
97
|
+
* assert.deepStrictEqual(
|
|
98
|
+
* StringX.replaceLineRange("a\nb\nc\nd", 1, 2, ["X"]),
|
|
99
|
+
* "a\nX\nd",
|
|
100
|
+
* )
|
|
101
|
+
*
|
|
102
|
+
* // an empty replacement deletes the range
|
|
103
|
+
* assert.deepStrictEqual(StringX.replaceLineRange("a\nb\nc\nd", 1, 2, []), "a\nd")
|
|
104
|
+
*
|
|
105
|
+
* // data-last (piped)
|
|
106
|
+
* assert.deepStrictEqual(
|
|
107
|
+
* pipe("a\nb\nc", StringX.replaceLineRange(1, 1, ["X", "Y"])),
|
|
108
|
+
* "a\nX\nY\nc",
|
|
109
|
+
* )
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @category combinators
|
|
113
|
+
* @since 0.0.0
|
|
114
|
+
*/
|
|
115
|
+
export const replaceLineRange = /*#__PURE__*/dual(4, (content, startLine, endLine, replacement) => {
|
|
116
|
+
const lines = content.split("\n");
|
|
117
|
+
return Array.join([...Array.take(lines, startLine), ...replacement, ...Array.drop(lines, endLine + 1)], "\n");
|
|
118
|
+
});
|
|
119
|
+
/**
|
|
120
|
+
* Inserts `lines` immediately before the line at `anchorIndex`, preserving the
|
|
121
|
+
* anchor line and everything after it; returns the rejoined string.
|
|
122
|
+
*
|
|
123
|
+
* `content` is split on `\n` and `lines` are spliced in just before the
|
|
124
|
+
* zero-based `anchorIndex`. An `anchorIndex` of `0` prepends, and one at or past
|
|
125
|
+
* the end appends.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* import { pipe } from "effect"
|
|
130
|
+
* import { StringX } from "@nunofyobiz/effect-extras"
|
|
131
|
+
*
|
|
132
|
+
* // data-first — insert before line 1, keeping the anchor and the rest
|
|
133
|
+
* assert.deepStrictEqual(StringX.insertBeforeLine("a\nb\nc", 1, ["X"]), "a\nX\nb\nc")
|
|
134
|
+
*
|
|
135
|
+
* // an anchor at the end appends
|
|
136
|
+
* assert.deepStrictEqual(StringX.insertBeforeLine("a\nb", 2, ["X"]), "a\nb\nX")
|
|
137
|
+
*
|
|
138
|
+
* // data-last (piped)
|
|
139
|
+
* assert.deepStrictEqual(pipe("a\nb", StringX.insertBeforeLine(0, ["X"])), "X\na\nb")
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @category combinators
|
|
143
|
+
* @since 0.0.0
|
|
144
|
+
*/
|
|
145
|
+
export const insertBeforeLine = /*#__PURE__*/dual(3, (content, anchorIndex, lines) => {
|
|
146
|
+
const split = content.split("\n");
|
|
147
|
+
return Array.join([...Array.take(split, anchorIndex), ...lines, ...Array.drop(split, anchorIndex)], "\n");
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=StringX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StringX.js","names":["Array","dual","prepend","string_","start","surround","end","ensurePrepend","startsWith","replaceLineRange","content","startLine","endLine","replacement","lines","split","join","take","drop","insertBeforeLine","anchorIndex"],"sources":["../src/StringX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,KAAK,QAAQ,QAAQ;AAC9B,SAASC,IAAI,QAAQ,iBAAiB;AAEtC;;;;;;;;;;;;;;;;;;;;;AAqBA,OAAO,MAAMC,OAAO,gBAAGD,IAAI,CAGzB,CAAC,EAAE,CAACE,OAAe,EAAEC,KAAa,KAAa,GAAGA,KAAK,GAAGD,OAAO,EAAE,CAAC;AAEtE;;;;;;;;;;;;;;;;;;;;AAoBA,OAAO,MAAME,QAAQ,gBAAGJ,IAAI,CAI1B,CAAC,EACD,CAACE,OAAe,EAAEC,KAAa,EAAEE,GAAW,KAC1C,GAAGF,KAAK,GAAGD,OAAO,GAAGG,GAAG,EAAE,CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,OAAO,MAAMC,aAAa,gBAAGN,IAAI,CAG/B,CAAC,EAAE,CAACE,OAAe,EAAEC,KAAa,KAAY;EAC9C,IAAID,OAAO,CAACK,UAAU,CAACJ,KAAK,CAAC,EAAE;IAC7B,OAAOD,OAAO;EAChB;EAEA,OAAO,GAAGC,KAAK,GAAGD,OAAO,EAAE;AAC7B,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,OAAO,MAAMM,gBAAgB,gBAAGR,IAAI,CAalC,CAAC,EACD,CACES,OAAe,EACfC,SAAiB,EACjBC,OAAe,EACfC,WAA8B,KACpB;EACV,MAAMC,KAAK,GAAGJ,OAAO,CAACK,KAAK,CAAC,IAAI,CAAC;EACjC,OAAOf,KAAK,CAACgB,IAAI,CACf,CACE,GAAGhB,KAAK,CAACiB,IAAI,CAACH,KAAK,EAAEH,SAAS,CAAC,EAC/B,GAAGE,WAAW,EACd,GAAGb,KAAK,CAACkB,IAAI,CAACJ,KAAK,EAAEF,OAAO,GAAG,CAAC,CAAC,CAClC,EACD,IAAI,CACL;AACH,CAAC,CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,OAAO,MAAMO,gBAAgB,gBAAGlB,IAAI,CAOlC,CAAC,EACD,CAACS,OAAe,EAAEU,WAAmB,EAAEN,KAAwB,KAAY;EACzE,MAAMC,KAAK,GAAGL,OAAO,CAACK,KAAK,CAAC,IAAI,CAAC;EACjC,OAAOf,KAAK,CAACgB,IAAI,CACf,CACE,GAAGhB,KAAK,CAACiB,IAAI,CAACF,KAAK,EAAEK,WAAW,CAAC,EACjC,GAAGN,KAAK,EACR,GAAGd,KAAK,CAACkB,IAAI,CAACH,KAAK,EAAEK,WAAW,CAAC,CAClC,EACD,IAAI,CACL;AACH,CAAC,CACF","ignoreList":[]}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions to Effect's `Struct` module.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Option } from "effect";
|
|
7
|
+
/**
|
|
8
|
+
* Describes the shape of a per-field transformation over an object `O`: a record
|
|
9
|
+
* `T` whose values are functions taking the corresponding field of `O`.
|
|
10
|
+
*
|
|
11
|
+
* Used to type the "evolve" pattern, where each provided key maps to a function
|
|
12
|
+
* that receives that field's current value. Copied from Effect's internal
|
|
13
|
+
* `Struct.evolve()` type, which is not exported — it would be better to use
|
|
14
|
+
* theirs directly if it ever becomes public.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { StructX } from "@nunofyobiz/effect-extras"
|
|
19
|
+
*
|
|
20
|
+
* type Transform = StructX.PartialTransform<
|
|
21
|
+
* { a: number; b: string },
|
|
22
|
+
* { a: (n: number) => boolean }
|
|
23
|
+
* >
|
|
24
|
+
*
|
|
25
|
+
* const evolve: Transform = { a: (n) => n > 0 }
|
|
26
|
+
*
|
|
27
|
+
* assert.deepStrictEqual(evolve.a(1), true)
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @category models
|
|
31
|
+
* @since 0.0.0
|
|
32
|
+
*/
|
|
33
|
+
export type PartialTransform<O, T> = {
|
|
34
|
+
[K in keyof T]: T[K] extends (a: O[K & keyof O]) => unknown ? T[K] : (a: O[K & keyof O]) => unknown;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Builds a singleton record `{ [name]: value }` when `value` is defined, or an
|
|
38
|
+
* empty object `{}` when it is `undefined` — meant to be spread into an object
|
|
39
|
+
* literal.
|
|
40
|
+
*
|
|
41
|
+
* This is the canonical fix for `exactOptionalPropertyTypes: true` (which this
|
|
42
|
+
* repo enables for Effect Schema). Under that flag, spreading
|
|
43
|
+
* `{ key: maybeUndefined }` into an object whose key is `key?: T` is a type
|
|
44
|
+
* error: the property must be *absent*, not present-but-`undefined`. Spreading
|
|
45
|
+
* `...defined("key", maybeUndefined)` instead conditionally omits the property
|
|
46
|
+
* altogether. Note that `null` and other falsy-but-defined values (`0`, `""`,
|
|
47
|
+
* `false`) are kept — only `undefined` is dropped.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { StructX } from "@nunofyobiz/effect-extras"
|
|
52
|
+
*
|
|
53
|
+
* // Defined value → singleton record
|
|
54
|
+
* assert.deepStrictEqual(StructX.defined("name", "Ada"), { name: "Ada" })
|
|
55
|
+
*
|
|
56
|
+
* // undefined → property omitted entirely
|
|
57
|
+
* assert.deepStrictEqual(StructX.defined("name", undefined), {})
|
|
58
|
+
*
|
|
59
|
+
* // Falsy-but-defined values are kept
|
|
60
|
+
* assert.deepStrictEqual(StructX.defined("name", 0), { name: 0 })
|
|
61
|
+
*
|
|
62
|
+
* // Typical use: spread to conditionally include an optional field
|
|
63
|
+
* const maybeAge: number | undefined = undefined
|
|
64
|
+
* assert.deepStrictEqual({ id: 1, ...StructX.defined("age", maybeAge) }, {
|
|
65
|
+
* id: 1,
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @category constructors
|
|
70
|
+
* @since 0.0.0
|
|
71
|
+
*/
|
|
72
|
+
export declare const defined: <const K extends string, V>(name: K, value: V | undefined) => Partial<Record<K, Exclude<V, undefined>>>;
|
|
73
|
+
/**
|
|
74
|
+
* Removes every property whose value is `undefined` from `record`, narrowing
|
|
75
|
+
* each remaining property type to exclude `undefined`.
|
|
76
|
+
*
|
|
77
|
+
* The bulk counterpart of {@link defined}: instead of building one optional
|
|
78
|
+
* field, it filters a whole object. Very useful for update/patch actions where
|
|
79
|
+
* `undefined` means "leave this field unchanged" while every other value —
|
|
80
|
+
* including `null`, `0`, `""`, `false`, and `Option.none()` — means "set the
|
|
81
|
+
* field to exactly this".
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* import { StructX } from "@nunofyobiz/effect-extras"
|
|
86
|
+
*
|
|
87
|
+
* // Drops `b` (undefined) but keeps every other value, including null/0/false
|
|
88
|
+
* assert.deepStrictEqual(
|
|
89
|
+
* StructX.filterDefined({ a: "x", b: undefined, c: 0, d: null, e: false }),
|
|
90
|
+
* { a: "x", c: 0, d: null, e: false },
|
|
91
|
+
* )
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @category filtering
|
|
95
|
+
* @since 0.0.0
|
|
96
|
+
*/
|
|
97
|
+
export declare const filterDefined: <R extends Record<string, unknown>>(record: R) => Partial<{ [P in keyof R]: Exclude<R[P], undefined>; }>;
|
|
98
|
+
/**
|
|
99
|
+
* Builds a singleton record `{ [name]: value }` when `value` is `Some`, or an
|
|
100
|
+
* empty object `{}` when it is `None` — meant to be spread into an object
|
|
101
|
+
* literal.
|
|
102
|
+
*
|
|
103
|
+
* The `Option`-valued sibling of {@link defined}: where `defined` keys off
|
|
104
|
+
* `undefined`, this keys off `Option` presence. Spread `...some("key", opt)` to
|
|
105
|
+
* conditionally include a field only when the `Option` carries a value, which
|
|
106
|
+
* stays correct under `exactOptionalPropertyTypes: true`.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* import { Option } from "effect"
|
|
111
|
+
* import { StructX } from "@nunofyobiz/effect-extras"
|
|
112
|
+
*
|
|
113
|
+
* // Some → singleton record
|
|
114
|
+
* assert.deepStrictEqual(StructX.some("name", Option.some("Ada")), {
|
|
115
|
+
* name: "Ada",
|
|
116
|
+
* })
|
|
117
|
+
*
|
|
118
|
+
* // None → property omitted entirely
|
|
119
|
+
* assert.deepStrictEqual(StructX.some("name", Option.none()), {})
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @category constructors
|
|
123
|
+
* @since 0.0.0
|
|
124
|
+
*/
|
|
125
|
+
export declare const some: <const K extends string, V>(name: K, value: Option.Option<V>) => Partial<Record<K, V>>;
|
|
126
|
+
/**
|
|
127
|
+
* Looks up `key` in a record of `Option` values and returns a singleton record
|
|
128
|
+
* when the value is `Some`, or `{}` when the key is absent or its value is
|
|
129
|
+
* `None`.
|
|
130
|
+
*
|
|
131
|
+
* Combines `Record.get` + `Option.flatten` + a singleton builder in one call —
|
|
132
|
+
* ideal for spreading an optional field out of a lookup table into an object
|
|
133
|
+
* literal under `exactOptionalPropertyTypes: true`. By default the output key
|
|
134
|
+
* matches the lookup key; pass `renameKeyTo` to emit the value under a different
|
|
135
|
+
* name.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* import { Option } from "effect"
|
|
140
|
+
* import { StructX } from "@nunofyobiz/effect-extras"
|
|
141
|
+
*
|
|
142
|
+
* const lookup = {
|
|
143
|
+
* a: Option.some(100),
|
|
144
|
+
* b: Option.none<number>(),
|
|
145
|
+
* }
|
|
146
|
+
*
|
|
147
|
+
* // Some → singleton record under the same key
|
|
148
|
+
* assert.deepStrictEqual(StructX.pickSome(lookup, "a"), { a: 100 })
|
|
149
|
+
*
|
|
150
|
+
* // None → property omitted entirely
|
|
151
|
+
* assert.deepStrictEqual(StructX.pickSome(lookup, "b"), {})
|
|
152
|
+
*
|
|
153
|
+
* // Rename the output key
|
|
154
|
+
* assert.deepStrictEqual(StructX.pickSome(lookup, "a", "count"), { count: 100 })
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @category constructors
|
|
158
|
+
* @since 0.0.0
|
|
159
|
+
*/
|
|
160
|
+
export declare function pickSome<const K extends string, V>(record: Record<K, Option.Option<V>>, key: K): Partial<Record<K, V>>;
|
|
161
|
+
export declare function pickSome<const K1 extends string, V, const K2 extends string>(record: Record<K1, Option.Option<V>>, key: K1, renameKeyTo: K2): Partial<Record<K2, V>>;
|
|
162
|
+
/**
|
|
163
|
+
* Builds a singleton record `{ [name]: value }` when `value` is truthy, or an
|
|
164
|
+
* empty object `{}` otherwise — meant to be spread into an object literal.
|
|
165
|
+
*
|
|
166
|
+
* Stricter than {@link defined}: it drops not just `undefined` but every falsy
|
|
167
|
+
* value (`null`, `false`, `0`, `""`, `NaN`), and narrows the value type
|
|
168
|
+
* accordingly. Use it to spread a field only when it carries a meaningful,
|
|
169
|
+
* non-falsy value.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* import { StructX } from "@nunofyobiz/effect-extras"
|
|
174
|
+
*
|
|
175
|
+
* // Truthy value → singleton record
|
|
176
|
+
* assert.deepStrictEqual(StructX.truthy("name", "Ada"), { name: "Ada" })
|
|
177
|
+
*
|
|
178
|
+
* // Falsy values → property omitted entirely
|
|
179
|
+
* assert.deepStrictEqual(StructX.truthy("name", ""), {})
|
|
180
|
+
* assert.deepStrictEqual(StructX.truthy("name", 0), {})
|
|
181
|
+
* assert.deepStrictEqual(StructX.truthy("name", false), {})
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* @category constructors
|
|
185
|
+
* @since 0.0.0
|
|
186
|
+
*/
|
|
187
|
+
export declare const truthy: <const K extends string, V>(name: K, value: V) => Partial<Record<K, Exclude<NonNullable<V>, false | 0 | "">>>;
|
|
188
|
+
/**
|
|
189
|
+
* Returns `true` when `object` has `key` set to a non-nullish value, narrowing
|
|
190
|
+
* that property to `NonNullable` on the type level.
|
|
191
|
+
*
|
|
192
|
+
* A type guard combining `hasProperty` with a nullish check: after a successful
|
|
193
|
+
* test, TypeScript treats `object[key]` as present and free of `null` /
|
|
194
|
+
* `undefined`. Handy as a predicate passed to `Array.filter` to keep only the
|
|
195
|
+
* elements whose `key` is populated.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* import { pipe } from "effect"
|
|
200
|
+
* import { StructX } from "@nunofyobiz/effect-extras"
|
|
201
|
+
*
|
|
202
|
+
* // data-first
|
|
203
|
+
* assert.deepStrictEqual(
|
|
204
|
+
* StructX.hasNotNullableProperty({ id: "1" }, "id"),
|
|
205
|
+
* true,
|
|
206
|
+
* )
|
|
207
|
+
*
|
|
208
|
+
* // data-last (pipeable); a null value fails the guard
|
|
209
|
+
* assert.deepStrictEqual(
|
|
210
|
+
* pipe({ id: null }, StructX.hasNotNullableProperty("id")),
|
|
211
|
+
* false,
|
|
212
|
+
* )
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* @category refinements
|
|
216
|
+
* @since 0.0.0
|
|
217
|
+
*/
|
|
218
|
+
export declare const hasNotNullableProperty: (<T, K extends keyof T>(key: K) => (object: T) => object is T & Record<K, NonNullable<T[K]>>) & (<T, K extends keyof T>(object: T, key: K) => object is T & Record<K, NonNullable<T[K]>>);
|
|
219
|
+
//# sourceMappingURL=StructX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StructX.d.ts","sourceRoot":"","sources":["../src/StructX.ts"],"names":[],"mappings":"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"}
|