@sladg/apex-state 3.5.0 → 3.6.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/dist/index.d.ts +100 -79
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/testing/index.js +5 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -121,6 +121,70 @@ type RecordLevel2<V, ParentKey extends string, Depth extends number> = IsAny$1<V
|
|
|
121
121
|
}[keyof V & (string | number)];
|
|
122
122
|
type Prev2<N extends number> = N extends 20 ? 18 : N extends 19 ? 17 : N extends 18 ? 16 : N extends 17 ? 15 : N extends 16 ? 14 : N extends 15 ? 13 : N extends 14 ? 12 : N extends 13 ? 11 : N extends 12 ? 10 : N extends 11 ? 9 : N extends 10 ? 8 : N extends 9 ? 7 : N extends 8 ? 6 : N extends 7 ? 5 : N extends 6 ? 4 : N extends 5 ? 3 : N extends 4 ? 2 : N extends 3 ? 1 : N extends 2 ? 0 : N extends 1 ? 0 : never;
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* DeepKeyFiltered - Filters paths by their resolved value type
|
|
126
|
+
*
|
|
127
|
+
* Returns only paths from DeepKey<T> that resolve to a specific type U.
|
|
128
|
+
* Useful for type-safe filtering of state paths by their value types.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* type Data = {
|
|
133
|
+
* isActive: boolean
|
|
134
|
+
* name: string
|
|
135
|
+
* count: number
|
|
136
|
+
* user: { isAdmin: boolean }
|
|
137
|
+
* }
|
|
138
|
+
*
|
|
139
|
+
* // Only boolean paths
|
|
140
|
+
* type BoolPaths = DeepKeyFiltered<Data, boolean>
|
|
141
|
+
* // Result: "isActive" | "user.isAdmin"
|
|
142
|
+
*
|
|
143
|
+
* // Only string paths
|
|
144
|
+
* type StrPaths = DeepKeyFiltered<Data, string>
|
|
145
|
+
* // Result: "name"
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Filters DeepKey<T> to only include paths that resolve to type U.
|
|
151
|
+
*
|
|
152
|
+
* Uses mapped type with conditional filtering - maps over all possible paths,
|
|
153
|
+
* keeps those matching the target type, and extracts the union.
|
|
154
|
+
*
|
|
155
|
+
* @example Custom depth — propagates to DeepKey
|
|
156
|
+
* ```typescript
|
|
157
|
+
* // Only number paths, limited to 10 levels deep
|
|
158
|
+
* type ShallowNumbers = DeepKeyFiltered<State, number, 10>
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
type DeepKeyFiltered<T, U, Depth extends number = DefaultDepth> = {
|
|
162
|
+
[K in ResolvableDeepKey<T, Depth>]: NonNullable<DeepValue<T, K>> extends U ? K : never;
|
|
163
|
+
}[ResolvableDeepKey<T, Depth>];
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* DeepValue utility type
|
|
167
|
+
*
|
|
168
|
+
* Extracts the value type for a given dot-notation path string.
|
|
169
|
+
* Handles nested objects, arrays, and optional properties.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* type User = {
|
|
174
|
+
* address: {
|
|
175
|
+
* street: string
|
|
176
|
+
* city: string
|
|
177
|
+
* }
|
|
178
|
+
* }
|
|
179
|
+
*
|
|
180
|
+
* // DeepValue<User, "address.street"> = string
|
|
181
|
+
* // DeepValue<User, "address"> = { street: string, city: string }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
186
|
+
type DeepValue<T, Path extends string> = IsAny<T> extends true ? never : T extends readonly any[] ? T[number] : Path extends `${infer First}.${infer Rest}` ? First extends keyof T ? DeepValue<T[First], Rest> : string extends keyof T ? First extends HASH_KEY ? DeepValue<T[string], Rest> : unknown : unknown : Path extends HASH_KEY ? string extends keyof T ? T[string] : unknown : Path extends keyof T ? T[Path] : unknown;
|
|
187
|
+
|
|
124
188
|
/**
|
|
125
189
|
* Boolean logic DSL type definitions
|
|
126
190
|
*
|
|
@@ -129,9 +193,23 @@ type Prev2<N extends number> = N extends 20 ? 18 : N extends 19 ? 17 : N extends
|
|
|
129
193
|
*/
|
|
130
194
|
|
|
131
195
|
/**
|
|
132
|
-
*
|
|
196
|
+
* Path-value pair distributed over all valid paths.
|
|
197
|
+
* Each path is paired with its resolved value type, ensuring type safety.
|
|
198
|
+
* The distribution happens inside the tuple, not at the union level —
|
|
199
|
+
* this keeps BoolLogic's top-level union flat so `in` narrowing works.
|
|
200
|
+
*/
|
|
201
|
+
type PathValuePair<STATE, Depth extends number> = DeepKey<STATE, Depth> extends infer P ? P extends string ? [P, DeepValue<STATE, P>] : never : never;
|
|
202
|
+
/**
|
|
203
|
+
* Path-value array pair for IN operator.
|
|
204
|
+
* Same distribution as PathValuePair but with array values.
|
|
205
|
+
*/
|
|
206
|
+
type PathValueArrayPair<STATE, Depth extends number> = DeepKey<STATE, Depth> extends infer P ? P extends string ? [P, DeepValue<STATE, P>[]] : never : never;
|
|
207
|
+
/**
|
|
208
|
+
* Paths that resolve to number, plus `.length` on array-valued paths.
|
|
209
|
+
* Allows GT/LT/GTE/LTE to compare against array lengths without
|
|
210
|
+
* polluting DeepKey with virtual paths.
|
|
133
211
|
*/
|
|
134
|
-
type
|
|
212
|
+
type NumericPaths<STATE, Depth extends number> = DeepKeyFiltered<STATE, number, Depth> | `${DeepKeyFiltered<STATE, readonly unknown[], Depth>}.length`;
|
|
135
213
|
/**
|
|
136
214
|
* Boolean logic DSL for conditional expressions
|
|
137
215
|
*
|
|
@@ -139,33 +217,40 @@ type ComparableValue = string | number | boolean | null | undefined;
|
|
|
139
217
|
* Used by concerns (disabledWhen, visibleWhen) and side effects.
|
|
140
218
|
*
|
|
141
219
|
* Operators:
|
|
142
|
-
* - IS_EQUAL: Compare path value to expected value
|
|
220
|
+
* - IS_EQUAL: Compare path value to expected value (value must match path type)
|
|
143
221
|
* - EXISTS: Check if path value is not null/undefined
|
|
144
222
|
* - IS_EMPTY: Check if path value is empty (string/array/object)
|
|
145
223
|
* - AND/OR/NOT: Boolean combinators
|
|
146
|
-
* - GT/LT/GTE/LTE: Numeric comparisons
|
|
147
|
-
* - IN: Check if path value is in allowed list
|
|
224
|
+
* - GT/LT/GTE/LTE: Numeric comparisons (only on number paths or array.length)
|
|
225
|
+
* - IN: Check if path value is in allowed list (values must match path type)
|
|
226
|
+
* - Shorthand: [path, value] tuple as shorthand for IS_EQUAL
|
|
148
227
|
*
|
|
149
228
|
* @example
|
|
150
229
|
* ```typescript
|
|
151
230
|
* // Simple equality check
|
|
152
231
|
* const isAdmin: BoolLogic<State> = { IS_EQUAL: ['user.role', 'admin'] }
|
|
153
232
|
*
|
|
154
|
-
* //
|
|
233
|
+
* // Shorthand equality (equivalent to IS_EQUAL)
|
|
234
|
+
* const isAdmin2: BoolLogic<State> = ['user.role', 'admin']
|
|
235
|
+
*
|
|
236
|
+
* // Combined conditions with shorthand
|
|
155
237
|
* const canEdit: BoolLogic<State> = {
|
|
156
238
|
* AND: [
|
|
157
|
-
*
|
|
239
|
+
* ['user.role', 'editor'],
|
|
158
240
|
* { EXISTS: 'document.id' },
|
|
159
|
-
* { NOT:
|
|
241
|
+
* { NOT: ['document.status', 'locked'] }
|
|
160
242
|
* ]
|
|
161
243
|
* }
|
|
162
244
|
*
|
|
163
245
|
* // Numeric comparison
|
|
164
246
|
* const isExpensive: BoolLogic<State> = { GT: ['product.price', 100] }
|
|
247
|
+
*
|
|
248
|
+
* // Array length comparison
|
|
249
|
+
* const hasManyItems: BoolLogic<State> = { GT: ['cart.items.length', 5] }
|
|
165
250
|
* ```
|
|
166
251
|
*/
|
|
167
252
|
type BoolLogic<STATE, Depth extends number = DefaultDepth> = {
|
|
168
|
-
IS_EQUAL:
|
|
253
|
+
IS_EQUAL: PathValuePair<STATE, Depth>;
|
|
169
254
|
} | {
|
|
170
255
|
EXISTS: DeepKey<STATE, Depth>;
|
|
171
256
|
} | {
|
|
@@ -177,39 +262,16 @@ type BoolLogic<STATE, Depth extends number = DefaultDepth> = {
|
|
|
177
262
|
} | {
|
|
178
263
|
NOT: BoolLogic<STATE, Depth>;
|
|
179
264
|
} | {
|
|
180
|
-
GT: [
|
|
265
|
+
GT: [NumericPaths<STATE, Depth>, number];
|
|
181
266
|
} | {
|
|
182
|
-
LT: [
|
|
267
|
+
LT: [NumericPaths<STATE, Depth>, number];
|
|
183
268
|
} | {
|
|
184
|
-
GTE: [
|
|
269
|
+
GTE: [NumericPaths<STATE, Depth>, number];
|
|
185
270
|
} | {
|
|
186
|
-
LTE: [
|
|
271
|
+
LTE: [NumericPaths<STATE, Depth>, number];
|
|
187
272
|
} | {
|
|
188
|
-
IN:
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* DeepValue utility type
|
|
193
|
-
*
|
|
194
|
-
* Extracts the value type for a given dot-notation path string.
|
|
195
|
-
* Handles nested objects, arrays, and optional properties.
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```typescript
|
|
199
|
-
* type User = {
|
|
200
|
-
* address: {
|
|
201
|
-
* street: string
|
|
202
|
-
* city: string
|
|
203
|
-
* }
|
|
204
|
-
* }
|
|
205
|
-
*
|
|
206
|
-
* // DeepValue<User, "address.street"> = string
|
|
207
|
-
* // DeepValue<User, "address"> = { street: string, city: string }
|
|
208
|
-
* ```
|
|
209
|
-
*/
|
|
210
|
-
|
|
211
|
-
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
212
|
-
type DeepValue<T, Path extends string> = IsAny<T> extends true ? never : T extends readonly any[] ? T[number] : Path extends `${infer First}.${infer Rest}` ? First extends keyof T ? DeepValue<T[First], Rest> : string extends keyof T ? First extends HASH_KEY ? DeepValue<T[string], Rest> : unknown : unknown : Path extends HASH_KEY ? string extends keyof T ? T[string] : unknown : Path extends keyof T ? T[Path] : unknown;
|
|
273
|
+
IN: PathValueArrayPair<STATE, Depth>;
|
|
274
|
+
} | PathValuePair<STATE, Depth>;
|
|
213
275
|
|
|
214
276
|
/**
|
|
215
277
|
* GenericMeta interface
|
|
@@ -422,47 +484,6 @@ type ConcernRegistrationMap<DATA extends object, CONCERNS extends readonly any[]
|
|
|
422
484
|
}>;
|
|
423
485
|
}>;
|
|
424
486
|
|
|
425
|
-
/**
|
|
426
|
-
* DeepKeyFiltered - Filters paths by their resolved value type
|
|
427
|
-
*
|
|
428
|
-
* Returns only paths from DeepKey<T> that resolve to a specific type U.
|
|
429
|
-
* Useful for type-safe filtering of state paths by their value types.
|
|
430
|
-
*
|
|
431
|
-
* @example
|
|
432
|
-
* ```typescript
|
|
433
|
-
* type Data = {
|
|
434
|
-
* isActive: boolean
|
|
435
|
-
* name: string
|
|
436
|
-
* count: number
|
|
437
|
-
* user: { isAdmin: boolean }
|
|
438
|
-
* }
|
|
439
|
-
*
|
|
440
|
-
* // Only boolean paths
|
|
441
|
-
* type BoolPaths = DeepKeyFiltered<Data, boolean>
|
|
442
|
-
* // Result: "isActive" | "user.isAdmin"
|
|
443
|
-
*
|
|
444
|
-
* // Only string paths
|
|
445
|
-
* type StrPaths = DeepKeyFiltered<Data, string>
|
|
446
|
-
* // Result: "name"
|
|
447
|
-
* ```
|
|
448
|
-
*/
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Filters DeepKey<T> to only include paths that resolve to type U.
|
|
452
|
-
*
|
|
453
|
-
* Uses mapped type with conditional filtering - maps over all possible paths,
|
|
454
|
-
* keeps those matching the target type, and extracts the union.
|
|
455
|
-
*
|
|
456
|
-
* @example Custom depth — propagates to DeepKey
|
|
457
|
-
* ```typescript
|
|
458
|
-
* // Only number paths, limited to 10 levels deep
|
|
459
|
-
* type ShallowNumbers = DeepKeyFiltered<State, number, 10>
|
|
460
|
-
* ```
|
|
461
|
-
*/
|
|
462
|
-
type DeepKeyFiltered<T, U, Depth extends number = DefaultDepth> = {
|
|
463
|
-
[K in ResolvableDeepKey<T, Depth>]: NonNullable<DeepValue<T, K>> extends U ? K : never;
|
|
464
|
-
}[ResolvableDeepKey<T, Depth>];
|
|
465
|
-
|
|
466
487
|
/**
|
|
467
488
|
* PathsOfSameValue - Type-safe path tuples for side effects
|
|
468
489
|
*
|