@ngxs/store 21.0.0 → 22.0.0-dev.master-8c6b0fc

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.
@@ -6,12 +6,28 @@ const isNumber = (value) => typeof value === 'number';
6
6
  const invalidIndex = (index) => Number.isNaN(index) || index === -1;
7
7
 
8
8
  /**
9
- * @param items - Specific items to append to the end of an array
9
+ * Adds items to the end of an array without mutating the original. Handles
10
+ * the case where the array property does not exist yet, so callers do not
11
+ * need to initialise it before appending. A `null`, `undefined`, or empty
12
+ * `items` argument is treated as a no-op to allow safe pass-through of
13
+ * optional data.
14
+ *
15
+ * @param items - Items to add to the end of the array.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * // Add a new zebra to the end of the list without touching the rest of state.
20
+ * ctx.setState(
21
+ * patch<AnimalsStateModel>({
22
+ * zebras: append<string>([action.payload])
23
+ * })
24
+ * );
25
+ * ```
10
26
  */
11
27
  function append(items) {
12
28
  return function appendOperator(existing) {
13
- // If `items` is `undefined` or `null` or `[]` but `existing` is provided
14
- // just return `existing`
29
+ // Nothing meaningful to append, so preserve the existing reference
30
+ // to avoid invalidating memoized selectors unnecessarily.
15
31
  const itemsNotProvidedButExistingIs = (!items || !items.length) && existing;
16
32
  if (itemsNotProvidedButExistingIs) {
17
33
  return existing;
@@ -19,12 +35,29 @@ function append(items) {
19
35
  if (isArray(existing)) {
20
36
  return existing.concat(items);
21
37
  }
22
- // For example if some property is added dynamically
23
- // and didn't exist before thus it's not `ArrayLike`
38
+ // The array property was never initialised, so `items` becomes the
39
+ // initial state rather than being appended to a non-existent array.
24
40
  return items;
25
41
  };
26
42
  }
27
43
 
44
+ /**
45
+ * Chains multiple state operators so they execute left-to-right, each
46
+ * receiving the output of the previous one. Useful when several independent
47
+ * transformations must be applied to the same state slice in a single atomic
48
+ * update, avoiding multiple `setState` calls.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * // Apply two independent array mutations in one atomic setState call.
53
+ * ctx.setState(
54
+ * compose<AnimalsStateModel>(
55
+ * patch({ zebras: append<string>([action.zebraName]) }),
56
+ * patch({ pandas: removeItem<string>(name => name === action.pandaToRemove) })
57
+ * )
58
+ * );
59
+ * ```
60
+ */
28
61
  function compose(...operators) {
29
62
  return function composeOperator(existing) {
30
63
  return operators.reduce((accumulator, operator) => operator(accumulator), existing);
@@ -32,32 +65,51 @@ function compose(...operators) {
32
65
  }
33
66
 
34
67
  function retrieveValue(operatorOrValue, existing) {
35
- // If state operator is a function
36
- // then call it with an original value
68
+ // Delegate to the operator so a derived transformation can be applied
69
+ // rather than substituting a static value.
37
70
  if (isStateOperator(operatorOrValue)) {
38
71
  const value = operatorOrValue(existing);
39
72
  return value;
40
73
  }
41
- // If operator or value was not provided
42
- // e.g. `elseOperatorOrValue` is `undefined`
43
- // then we just return an original value
74
+ // No else branch was provided, so leave the state unchanged.
44
75
  if (operatorOrValue === undefined) {
45
76
  return existing;
46
77
  }
47
78
  return operatorOrValue;
48
79
  }
49
80
  /**
50
- * @param condition - Condition can be a plain boolean value or a function,
51
- * that returns boolean, also this function can take a value as an argument
52
- * to which this state operator applies
53
- * @param trueOperatorOrValue - Any value or a state operator
54
- * @param elseOperatorOrValue - Any value or a state operator
81
+ * Applies one of two operators (or values) based on a condition, keeping
82
+ * conditional logic out of action handlers and inside the state mutation
83
+ * pipeline where it belongs.
84
+ *
85
+ * @param condition - A boolean or a predicate receiving the current state value.
86
+ * Use a predicate when the decision depends on the existing state rather than
87
+ * external data available at dispatch time.
88
+ * @param trueOperatorOrValue - Applied when `condition` is truthy.
89
+ * @param elseOperatorOrValue - Applied when `condition` is falsy. Omit to
90
+ * leave the state unchanged in the false branch.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * // Only add a panda when the list has fewer than 5 — the cap is enforced
95
+ * // inside the operator so the action handler stays free of branching logic.
96
+ * ctx.setState(
97
+ * patch<AnimalsStateModel>({
98
+ * pandas: iif(
99
+ * pandas => pandas.length < 5,
100
+ * append<string>([action.payload])
101
+ * )
102
+ * })
103
+ * );
104
+ * ```
55
105
  */
56
106
  function iif(condition, trueOperatorOrValue, elseOperatorOrValue) {
57
107
  return function iifOperator(existing) {
58
- // Convert the value to a boolean
108
+ // Normalise to a boolean so both plain booleans and predicates
109
+ // share the same resolution path below.
59
110
  let result = !!condition;
60
- // but if it is a function then run it to get the result
111
+ // Predicates receive the current state value so the decision can be
112
+ // based on live state rather than values captured at dispatch time.
61
113
  if (isPredicate(condition)) {
62
114
  result = condition(existing);
63
115
  }
@@ -69,25 +121,51 @@ function iif(condition, trueOperatorOrValue, elseOperatorOrValue) {
69
121
  }
70
122
 
71
123
  /**
72
- * @param value - Value to insert
73
- * @param [beforePosition] - Specified index to insert value before, optional
124
+ * Inserts an item into an array without mutating the original, satisfying
125
+ * NGXS's immutability requirement. Handles the case where the array property
126
+ * does not exist yet, so callers do not need to initialise it first.
127
+ *
128
+ * @param value - The item to insert. A `null` or `undefined` value is a no-op
129
+ * so that callers can pass through optional data safely.
130
+ * @param beforePosition - Index before which to insert. Omit (or pass a
131
+ * non-positive number) to prepend to the beginning of the array.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * // Prepend a new zebra (no position = insert at index 0).
136
+ * ctx.setState(
137
+ * patch<AnimalsStateModel>({
138
+ * zebras: insertItem<string>(action.payload)
139
+ * })
140
+ * );
141
+ * ```
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * // Insert before index 2, shifting subsequent items right.
146
+ * ctx.setState(
147
+ * patch<AnimalsStateModel>({
148
+ * zebras: insertItem<string>(action.payload, 2)
149
+ * })
150
+ * );
151
+ * ```
74
152
  */
75
153
  function insertItem(value, beforePosition) {
76
154
  return function insertItemOperator(existing) {
77
- // Have to check explicitly for `null` and `undefined`
78
- // because `value` can be `0`, thus `!value` will return `true`
155
+ // `== null` covers both `null` and `undefined` while letting falsy
156
+ // values like `0` or `false` through, where `!value` would not.
79
157
  if (value == null && existing) {
80
158
  return existing;
81
159
  }
82
- // Property may be dynamic and might not existed before
160
+ // The array property may not have been initialised yet; treat it as
161
+ // empty so callers don't have to guard against that case themselves.
83
162
  if (!isArray(existing)) {
84
163
  return [value];
85
164
  }
86
165
  const clone = existing.slice();
87
166
  let index = 0;
88
- // No need to call `isNumber`
89
- // as we are checking `> 0` not `>= 0`
90
- // everything except number will return false here
167
+ // `> 0` rather than `>= 0` intentionally: non-numeric values coerce
168
+ // to NaN and fail this check, so no explicit `isNumber` call is needed.
91
169
  if (beforePosition > 0) {
92
170
  index = beforePosition;
93
171
  }
@@ -96,6 +174,40 @@ function insertItem(value, beforePosition) {
96
174
  };
97
175
  }
98
176
 
177
+ /**
178
+ * Applies a partial update to a state object, only cloning it when at least
179
+ * one property actually changes. This preserves referential equality for
180
+ * unchanged states, preventing unnecessary re-renders in `OnPush` components
181
+ * and keeping memoized selectors from recalculating.
182
+ *
183
+ * Each property in `patchObject` can itself be a state operator, enabling
184
+ * nested immutable updates without manually spreading every level of the tree.
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * // Add an optional property to a state slice without touching existing ones.
189
+ * ctx.setState(
190
+ * patch<AnimalsStateModel>({ monkeys: [] })
191
+ * );
192
+ * ```
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * // Deep update — specify explicit types at each level so TypeScript can
197
+ * // catch property name mistakes in nested patches.
198
+ * ctx.setState(
199
+ * patch<AddressStateModel>({
200
+ * country: patch<AddressStateModel['country']>({
201
+ * city: patch<AddressStateModel['country']['city']>({
202
+ * address: patch<AddressStateModel['country']['city']['address']>({
203
+ * line1: action.line1
204
+ * })
205
+ * })
206
+ * })
207
+ * })
208
+ * );
209
+ * ```
210
+ */
99
211
  function patch(patchObject) {
100
212
  return function patchStateOperator(existing) {
101
213
  let clone = null;
@@ -117,10 +229,55 @@ function patch(patchObject) {
117
229
  }
118
230
 
119
231
  /**
120
- * @param selector - Index of item in the array or a predicate function
121
- * that can be provided in `Array.prototype.findIndex`
122
- * @param operatorOrValue - New value under the `selector` index or a
123
- * function that can be applied to an existing value
232
+ * Like `patch`, but safe to call when the state slice is `null` or
233
+ * `undefined`. Treats a missing slice as an empty object so the patch is
234
+ * applied against a clean baseline rather than throwing. Useful for lazily
235
+ * initialised state properties or optional sub-states that may not have been
236
+ * set yet.
237
+ *
238
+ * @example
239
+ * ```ts
240
+ * // Update a nested preferences slice that starts as null — no prior
241
+ * // null-check needed; safePatch treats null as an empty object.
242
+ * ctx.setState(
243
+ * patch<UserStateModel>({
244
+ * preferences: safePatch<UserPreferences>({ theme: action.theme })
245
+ * })
246
+ * );
247
+ * ```
248
+ */
249
+ function safePatch(patchSpec) {
250
+ const patcher = patch(patchSpec);
251
+ return function patchSafely(existing) {
252
+ return patcher(existing ?? {});
253
+ };
254
+ }
255
+
256
+ /**
257
+ * Replaces or transforms a single array element without cloning elements that
258
+ * did not change, preserving referential equality for the rest of the array.
259
+ * Returns the original array reference when nothing changed, keeping
260
+ * memoized selectors and `OnPush` components from re-rendering unnecessarily.
261
+ *
262
+ * @param selector - The index to update, or a predicate used to locate the
263
+ * item. Prefer a predicate when the item's position may have shifted since the
264
+ * index was last known.
265
+ * @param operatorOrValue - The replacement value, or a state operator applied
266
+ * to the existing element when a derived update is needed.
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * // Rename a panda — locate it by current name so the index doesn't need
271
+ * // to be known ahead of time.
272
+ * ctx.setState(
273
+ * patch<AnimalsStateModel>({
274
+ * pandas: updateItem<string>(
275
+ * name => name === action.payload.name,
276
+ * action.payload.newName
277
+ * )
278
+ * })
279
+ * );
280
+ * ```
124
281
  */
125
282
  function updateItem(selector, operatorOrValue) {
126
283
  return function updateItemOperator(existing) {
@@ -135,8 +292,8 @@ function updateItem(selector, operatorOrValue) {
135
292
  return existing;
136
293
  }
137
294
  let value = null;
138
- // Need to check if the new item value will change the existing item value
139
- // then, only if it will change it then clone the array and set the item
295
+ // Resolve the new value before touching the array so we can bail out
296
+ // early and skip the clone when nothing actually changed.
140
297
  const theOperatorOrValue = operatorOrValue;
141
298
  if (isStateOperator(theOperatorOrValue)) {
142
299
  value = theOperatorOrValue(existing[index]);
@@ -144,8 +301,8 @@ function updateItem(selector, operatorOrValue) {
144
301
  else {
145
302
  value = theOperatorOrValue;
146
303
  }
147
- // If the value hasn't been mutated
148
- // then we just return `existing` array
304
+ // Return the original reference to prevent memoized selectors and
305
+ // OnPush components from reacting to a no-op update.
149
306
  if (value === existing[index]) {
150
307
  return existing;
151
308
  }
@@ -156,7 +313,80 @@ function updateItem(selector, operatorOrValue) {
156
313
  }
157
314
 
158
315
  /**
159
- * @param selector - index or predicate to remove an item from an array by
316
+ * Replaces or transforms every array element that matches the predicate.
317
+ * Unlike `updateItem`, which stops at the first match, this operator walks
318
+ * the entire array so all qualifying elements are updated in one pass.
319
+ *
320
+ * Returns the original array reference unchanged when no elements match the
321
+ * predicate, preserving referential equality for memoized selectors. A new
322
+ * array is returned only when at least one element was actually updated.
323
+ *
324
+ * @param selector - Predicate used to decide which elements to update.
325
+ * @param operatorOrValue - Replacement value, or a state operator applied
326
+ * to each matching element when a derived update is needed.
327
+ *
328
+ * @example
329
+ * ```ts
330
+ * // Mark every inactive animal as active in one setState call.
331
+ * ctx.setState(
332
+ * patch<AnimalsStateModel>({
333
+ * animals: updateItems<Animal>(
334
+ * animal => !animal.active,
335
+ * patch({ active: true })
336
+ * )
337
+ * })
338
+ * );
339
+ * ```
340
+ */
341
+ function updateItems(selector, operatorOrValue) {
342
+ return function updateItemsOperator(existing) {
343
+ if (!Array.isArray(existing)) {
344
+ return [];
345
+ }
346
+ else if (existing.length === 0) {
347
+ return existing;
348
+ }
349
+ const clone = existing.slice();
350
+ let updated = false;
351
+ for (let index = 0; index < clone.length; index++) {
352
+ let value = clone[index];
353
+ if (selector(value)) {
354
+ const theOperatorOrValue = operatorOrValue;
355
+ if (isStateOperator(theOperatorOrValue)) {
356
+ value = theOperatorOrValue(value);
357
+ }
358
+ else {
359
+ value = theOperatorOrValue;
360
+ }
361
+ clone[index] = value;
362
+ updated = true;
363
+ }
364
+ }
365
+ // Return the original reference when nothing was updated to avoid
366
+ // invalidating memoized selectors on a no-op call.
367
+ return updated ? clone : existing;
368
+ };
369
+ }
370
+
371
+ /**
372
+ * Removes a single element from an array without mutating the original.
373
+ * Returns the original array reference when no matching item is found, so
374
+ * memoized selectors are not invalidated by a no-op removal.
375
+ *
376
+ * @param selector - The index to remove, or a predicate used to locate the
377
+ * item. Prefer a predicate when the item's position is not guaranteed to be
378
+ * stable across concurrent state updates.
379
+ *
380
+ * @example
381
+ * ```ts
382
+ * // Remove a panda by name — a predicate is safer than a hard-coded index
383
+ * // because the array order may change between dispatch and execution.
384
+ * ctx.setState(
385
+ * patch<AnimalsStateModel>({
386
+ * pandas: removeItem<string>(name => name === action.payload)
387
+ * })
388
+ * );
389
+ * ```
160
390
  */
161
391
  function removeItem(selector) {
162
392
  return function removeItemOperator(existing) {
@@ -176,6 +406,52 @@ function removeItem(selector) {
176
406
  };
177
407
  }
178
408
 
409
+ /**
410
+ * Removes every array element that matches the predicate. Unlike `removeItem`,
411
+ * which stops at the first match, this operator walks the entire array so all
412
+ * qualifying elements are eliminated in one pass.
413
+ *
414
+ * Returns the original array reference when no elements matched, so memoized
415
+ * selectors are not invalidated by a no-op removal.
416
+ *
417
+ * @param selector - Predicate used to decide which elements to remove.
418
+ * Elements for which the predicate returns `true` are dropped; the rest are kept.
419
+ *
420
+ * @example
421
+ * ```ts
422
+ * // Remove all inactive animals in one setState call.
423
+ * ctx.setState(
424
+ * patch<AnimalsStateModel>({
425
+ * animals: removeItems<Animal>(animal => !animal.active)
426
+ * })
427
+ * );
428
+ * ```
429
+ */
430
+ function removeItems(selector) {
431
+ return function removeItemsOperator(existing) {
432
+ if (!Array.isArray(existing)) {
433
+ return [];
434
+ }
435
+ else if (existing.length === 0) {
436
+ return existing;
437
+ }
438
+ const newValues = [];
439
+ for (let index = 0; index < existing.length; index++) {
440
+ const value = existing[index];
441
+ // Keep elements that do NOT match — the predicate describes what to remove.
442
+ if (selector(value) === false) {
443
+ newValues.push(value);
444
+ }
445
+ }
446
+ // Return the original reference when nothing was removed to avoid
447
+ // invalidating memoized selectors on a no-op call.
448
+ // Note: checking length equality (not `newValues.length > 0`) is
449
+ // intentional — the latter would incorrectly return `existing` when
450
+ // all elements were removed and `newValues` is empty.
451
+ return newValues.length === existing.length ? existing : newValues;
452
+ };
453
+ }
454
+
179
455
  /**
180
456
  * @module
181
457
  * @description
@@ -186,5 +462,5 @@ function removeItem(selector) {
186
462
  * Generated bundle index. Do not edit.
187
463
  */
188
464
 
189
- export { append, compose, iif, insertItem, isPredicate, isStateOperator, patch, removeItem, updateItem };
465
+ export { append, compose, iif, insertItem, isPredicate, isStateOperator, patch, removeItem, removeItems, safePatch, updateItem, updateItems };
190
466
  //# sourceMappingURL=ngxs-store-operators.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ngxs-store-operators.mjs","sources":["../../../packages/store/operators/src/utils.ts","../../../packages/store/operators/src/append.ts","../../../packages/store/operators/src/compose.ts","../../../packages/store/operators/src/iif.ts","../../../packages/store/operators/src/insert-item.ts","../../../packages/store/operators/src/patch.ts","../../../packages/store/operators/src/update-item.ts","../../../packages/store/operators/src/remove-item.ts","../../../packages/store/operators/src/index.ts","../../../packages/store/operators/src/ngxs-store-operators.ts"],"sourcesContent":["import { StateOperator } from './types';\n\nexport const isArray = Array.isArray;\n\nexport type Predicate<T = any> = (value: T | Readonly<T>) => boolean;\n\nconst isFunction = (value: unknown) => typeof value == 'function';\n\nexport const isStateOperator = isFunction as <T>(\n value: T | StateOperator<T>\n) => value is StateOperator<T>;\n\nexport const isPredicate = isFunction as <T>(\n value: Predicate<T> | boolean | number\n) => value is Predicate<T>;\n\nexport const isNumber = (value: unknown): value is number => typeof value === 'number';\n\nexport const invalidIndex = (index: number) => Number.isNaN(index) || index === -1;\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isArray } from './utils';\n\n/**\n * @param items - Specific items to append to the end of an array\n */\nexport function append<T>(items: NoInfer<T[]>): StateOperator<T[]> {\n return function appendOperator(existing: ExistingState<T[]>): T[] {\n // If `items` is `undefined` or `null` or `[]` but `existing` is provided\n // just return `existing`\n const itemsNotProvidedButExistingIs = (!items || !items.length) && existing;\n if (itemsNotProvidedButExistingIs) {\n return existing as unknown as T[];\n }\n\n if (isArray(existing)) {\n return existing.concat(items as unknown as ExistingState<T[]>);\n }\n\n // For example if some property is added dynamically\n // and didn't exist before thus it's not `ArrayLike`\n return items as unknown as T[];\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\n\nexport function compose<T>(...operators: NoInfer<StateOperator<T>[]>): StateOperator<T> {\n return function composeOperator(existing: ExistingState<T>): T {\n return operators.reduce(\n (accumulator, operator) => operator(accumulator as ExistingState<T>),\n existing as T\n );\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\n\nimport { isStateOperator, isPredicate, Predicate } from './utils';\n\nfunction retrieveValue<T>(\n operatorOrValue: StateOperator<T> | T,\n existing: ExistingState<T>\n): T {\n // If state operator is a function\n // then call it with an original value\n if (isStateOperator(operatorOrValue)) {\n const value = operatorOrValue(existing);\n return value as T;\n }\n\n // If operator or value was not provided\n // e.g. `elseOperatorOrValue` is `undefined`\n // then we just return an original value\n if (operatorOrValue === undefined) {\n return existing as T;\n }\n\n return operatorOrValue as T;\n}\n\n/**\n * @param condition - Condition can be a plain boolean value or a function,\n * that returns boolean, also this function can take a value as an argument\n * to which this state operator applies\n * @param trueOperatorOrValue - Any value or a state operator\n * @param elseOperatorOrValue - Any value or a state operator\n */\nexport function iif<T>(\n condition: NoInfer<Predicate<T>> | boolean,\n trueOperatorOrValue: NoInfer<StateOperator<T> | T>,\n elseOperatorOrValue?: NoInfer<StateOperator<T> | T>\n): StateOperator<T> {\n return function iifOperator(existing: ExistingState<T>): T {\n // Convert the value to a boolean\n let result = !!condition;\n // but if it is a function then run it to get the result\n if (isPredicate(condition)) {\n result = condition(existing as T);\n }\n\n if (result) {\n return retrieveValue<T>(trueOperatorOrValue as StateOperator<T> | T, existing);\n }\n\n return retrieveValue<T>(elseOperatorOrValue! as StateOperator<T> | T, existing);\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isArray } from './utils';\n\n/**\n * @param value - Value to insert\n * @param [beforePosition] - Specified index to insert value before, optional\n */\nexport function insertItem<T>(value: NoInfer<T>, beforePosition?: number): StateOperator<T[]> {\n return function insertItemOperator(existing: ExistingState<T[]>): T[] {\n // Have to check explicitly for `null` and `undefined`\n // because `value` can be `0`, thus `!value` will return `true`\n if (value == null && existing) {\n return existing as T[];\n }\n\n // Property may be dynamic and might not existed before\n if (!isArray(existing)) {\n return [value as unknown as T];\n }\n\n const clone = existing.slice();\n\n let index = 0;\n\n // No need to call `isNumber`\n // as we are checking `> 0` not `>= 0`\n // everything except number will return false here\n if (beforePosition! > 0) {\n index = beforePosition!;\n }\n\n clone.splice(index, 0, value as unknown as T);\n return clone;\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isStateOperator } from './utils';\n\ntype NotUndefined<T> = T extends undefined ? never : T;\n\nexport type ɵPatchSpec<T> = { [P in keyof T]?: T[P] | StateOperator<NotUndefined<T[P]>> };\n\nexport function patch<T extends Record<string, any>>(\n patchObject: NoInfer<ɵPatchSpec<T>>\n): StateOperator<T> {\n return function patchStateOperator(existing: ExistingState<T>): T {\n let clone = null;\n for (const k in patchObject) {\n const newValue = patchObject[k];\n const existingPropValue = existing?.[k];\n const newPropValue = isStateOperator(newValue)\n ? newValue(<any>existingPropValue)\n : newValue;\n if (newPropValue !== existingPropValue) {\n if (!clone) {\n clone = { ...(<any>existing) };\n }\n clone[k] = newPropValue;\n }\n }\n return clone || existing;\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\n\nimport { isStateOperator, isPredicate, isNumber, invalidIndex, Predicate } from './utils';\n\n/**\n * @param selector - Index of item in the array or a predicate function\n * that can be provided in `Array.prototype.findIndex`\n * @param operatorOrValue - New value under the `selector` index or a\n * function that can be applied to an existing value\n */\nexport function updateItem<T>(\n selector: number | NoInfer<Predicate<T>>,\n operatorOrValue: NoInfer<T> | NoInfer<StateOperator<T>>\n): StateOperator<T[]> {\n return function updateItemOperator(existing: ExistingState<T[]>): T[] {\n let index = -1;\n\n if (isPredicate(selector)) {\n index = existing.findIndex(selector as Predicate<T>);\n } else if (isNumber(selector)) {\n index = selector;\n }\n\n if (invalidIndex(index)) {\n return existing as T[];\n }\n\n let value: T = null!;\n // Need to check if the new item value will change the existing item value\n // then, only if it will change it then clone the array and set the item\n const theOperatorOrValue = operatorOrValue as T | StateOperator<T>;\n if (isStateOperator(theOperatorOrValue)) {\n value = theOperatorOrValue(existing[index] as ExistingState<T>);\n } else {\n value = theOperatorOrValue;\n }\n\n // If the value hasn't been mutated\n // then we just return `existing` array\n if (value === existing[index]) {\n return existing as T[];\n }\n\n const clone = existing.slice();\n clone[index] = value as T;\n return clone;\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isPredicate, isNumber, invalidIndex, Predicate } from './utils';\n\n/**\n * @param selector - index or predicate to remove an item from an array by\n */\nexport function removeItem<T>(selector: number | NoInfer<Predicate<T>>): StateOperator<T[]> {\n return function removeItemOperator(existing: ExistingState<T[]>): T[] {\n let index = -1;\n\n if (isPredicate(selector)) {\n index = existing.findIndex(selector);\n } else if (isNumber(selector)) {\n index = selector;\n }\n\n if (invalidIndex(index)) {\n return existing as T[];\n }\n\n const clone = existing.slice();\n clone.splice(index, 1);\n return clone;\n };\n}\n","/**\n * @module\n * @description\n * Entry point for all public APIs of this package.\n */\nexport { append } from './append';\nexport { compose } from './compose';\nexport { iif } from './iif';\nexport { insertItem } from './insert-item';\nexport { patch, type ɵPatchSpec } from './patch';\nexport { isStateOperator, isPredicate, type Predicate } from './utils';\nexport { updateItem } from './update-item';\nexport { removeItem } from './remove-item';\nexport type { ExistingState, NoInfer, StateOperator } from './types';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngxs-store-operators.mjs","sources":["../../../packages/store/operators/src/utils.ts","../../../packages/store/operators/src/append.ts","../../../packages/store/operators/src/compose.ts","../../../packages/store/operators/src/iif.ts","../../../packages/store/operators/src/insert-item.ts","../../../packages/store/operators/src/patch.ts","../../../packages/store/operators/src/safe-patch.ts","../../../packages/store/operators/src/update-item.ts","../../../packages/store/operators/src/update-items.ts","../../../packages/store/operators/src/remove-item.ts","../../../packages/store/operators/src/remove-items.ts","../../../packages/store/operators/src/index.ts","../../../packages/store/operators/src/ngxs-store-operators.ts"],"sourcesContent":["import { StateOperator } from './types';\n\nexport const isArray = Array.isArray;\n\nexport type Predicate<T = any> = (value: T | Readonly<T>) => boolean;\n\nconst isFunction = (value: unknown) => typeof value == 'function';\n\nexport const isStateOperator = isFunction as <T>(\n value: T | StateOperator<T>\n) => value is StateOperator<T>;\n\nexport const isPredicate = isFunction as <T>(\n value: Predicate<T> | boolean | number\n) => value is Predicate<T>;\n\nexport const isNumber = (value: unknown): value is number => typeof value === 'number';\n\nexport const invalidIndex = (index: number) => Number.isNaN(index) || index === -1;\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isArray } from './utils';\n\n/**\n * Adds items to the end of an array without mutating the original. Handles\n * the case where the array property does not exist yet, so callers do not\n * need to initialise it before appending. A `null`, `undefined`, or empty\n * `items` argument is treated as a no-op to allow safe pass-through of\n * optional data.\n *\n * @param items - Items to add to the end of the array.\n *\n * @example\n * ```ts\n * // Add a new zebra to the end of the list without touching the rest of state.\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * zebras: append<string>([action.payload])\n * })\n * );\n * ```\n */\nexport function append<T>(items: NoInfer<T[]>): StateOperator<T[]> {\n return function appendOperator(existing: ExistingState<T[]>): T[] {\n // Nothing meaningful to append, so preserve the existing reference\n // to avoid invalidating memoized selectors unnecessarily.\n const itemsNotProvidedButExistingIs = (!items || !items.length) && existing;\n if (itemsNotProvidedButExistingIs) {\n return existing as unknown as T[];\n }\n\n if (isArray(existing)) {\n return existing.concat(items as unknown as ExistingState<T[]>);\n }\n\n // The array property was never initialised, so `items` becomes the\n // initial state rather than being appended to a non-existent array.\n return items as unknown as T[];\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\n\n/**\n * Chains multiple state operators so they execute left-to-right, each\n * receiving the output of the previous one. Useful when several independent\n * transformations must be applied to the same state slice in a single atomic\n * update, avoiding multiple `setState` calls.\n *\n * @example\n * ```ts\n * // Apply two independent array mutations in one atomic setState call.\n * ctx.setState(\n * compose<AnimalsStateModel>(\n * patch({ zebras: append<string>([action.zebraName]) }),\n * patch({ pandas: removeItem<string>(name => name === action.pandaToRemove) })\n * )\n * );\n * ```\n */\nexport function compose<T>(...operators: NoInfer<StateOperator<T>[]>): StateOperator<T> {\n return function composeOperator(existing: ExistingState<T>): T {\n return operators.reduce(\n (accumulator, operator) => operator(accumulator as ExistingState<T>),\n existing as T\n );\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\n\nimport { isStateOperator, isPredicate, Predicate } from './utils';\n\nfunction retrieveValue<T>(\n operatorOrValue: StateOperator<T> | T,\n existing: ExistingState<T>\n): T {\n // Delegate to the operator so a derived transformation can be applied\n // rather than substituting a static value.\n if (isStateOperator(operatorOrValue)) {\n const value = operatorOrValue(existing);\n return value as T;\n }\n\n // No else branch was provided, so leave the state unchanged.\n if (operatorOrValue === undefined) {\n return existing as T;\n }\n\n return operatorOrValue as T;\n}\n\n/**\n * Applies one of two operators (or values) based on a condition, keeping\n * conditional logic out of action handlers and inside the state mutation\n * pipeline where it belongs.\n *\n * @param condition - A boolean or a predicate receiving the current state value.\n * Use a predicate when the decision depends on the existing state rather than\n * external data available at dispatch time.\n * @param trueOperatorOrValue - Applied when `condition` is truthy.\n * @param elseOperatorOrValue - Applied when `condition` is falsy. Omit to\n * leave the state unchanged in the false branch.\n *\n * @example\n * ```ts\n * // Only add a panda when the list has fewer than 5 — the cap is enforced\n * // inside the operator so the action handler stays free of branching logic.\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * pandas: iif(\n * pandas => pandas.length < 5,\n * append<string>([action.payload])\n * )\n * })\n * );\n * ```\n */\nexport function iif<T>(\n condition: NoInfer<Predicate<T>> | boolean,\n trueOperatorOrValue: NoInfer<StateOperator<T> | T>,\n elseOperatorOrValue?: NoInfer<StateOperator<T> | T>\n): StateOperator<T> {\n return function iifOperator(existing: ExistingState<T>): T {\n // Normalise to a boolean so both plain booleans and predicates\n // share the same resolution path below.\n let result = !!condition;\n // Predicates receive the current state value so the decision can be\n // based on live state rather than values captured at dispatch time.\n if (isPredicate(condition)) {\n result = condition(existing as T);\n }\n\n if (result) {\n return retrieveValue<T>(trueOperatorOrValue as StateOperator<T> | T, existing);\n }\n\n return retrieveValue<T>(elseOperatorOrValue! as StateOperator<T> | T, existing);\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isArray } from './utils';\n\n/**\n * Inserts an item into an array without mutating the original, satisfying\n * NGXS's immutability requirement. Handles the case where the array property\n * does not exist yet, so callers do not need to initialise it first.\n *\n * @param value - The item to insert. A `null` or `undefined` value is a no-op\n * so that callers can pass through optional data safely.\n * @param beforePosition - Index before which to insert. Omit (or pass a\n * non-positive number) to prepend to the beginning of the array.\n *\n * @example\n * ```ts\n * // Prepend a new zebra (no position = insert at index 0).\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * zebras: insertItem<string>(action.payload)\n * })\n * );\n * ```\n *\n * @example\n * ```ts\n * // Insert before index 2, shifting subsequent items right.\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * zebras: insertItem<string>(action.payload, 2)\n * })\n * );\n * ```\n */\nexport function insertItem<T>(value: NoInfer<T>, beforePosition?: number): StateOperator<T[]> {\n return function insertItemOperator(existing: ExistingState<T[]>): T[] {\n // `== null` covers both `null` and `undefined` while letting falsy\n // values like `0` or `false` through, where `!value` would not.\n if (value == null && existing) {\n return existing as T[];\n }\n\n // The array property may not have been initialised yet; treat it as\n // empty so callers don't have to guard against that case themselves.\n if (!isArray(existing)) {\n return [value as unknown as T];\n }\n\n const clone = existing.slice();\n\n let index = 0;\n\n // `> 0` rather than `>= 0` intentionally: non-numeric values coerce\n // to NaN and fail this check, so no explicit `isNumber` call is needed.\n if (beforePosition! > 0) {\n index = beforePosition!;\n }\n\n clone.splice(index, 0, value as unknown as T);\n return clone;\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isStateOperator } from './utils';\n\ntype NotUndefined<T> = T extends undefined ? never : T;\n\nexport type ɵPatchSpec<T> = { [P in keyof T]?: T[P] | StateOperator<NotUndefined<T[P]>> };\n\n/**\n * Applies a partial update to a state object, only cloning it when at least\n * one property actually changes. This preserves referential equality for\n * unchanged states, preventing unnecessary re-renders in `OnPush` components\n * and keeping memoized selectors from recalculating.\n *\n * Each property in `patchObject` can itself be a state operator, enabling\n * nested immutable updates without manually spreading every level of the tree.\n *\n * @example\n * ```ts\n * // Add an optional property to a state slice without touching existing ones.\n * ctx.setState(\n * patch<AnimalsStateModel>({ monkeys: [] })\n * );\n * ```\n *\n * @example\n * ```ts\n * // Deep update — specify explicit types at each level so TypeScript can\n * // catch property name mistakes in nested patches.\n * ctx.setState(\n * patch<AddressStateModel>({\n * country: patch<AddressStateModel['country']>({\n * city: patch<AddressStateModel['country']['city']>({\n * address: patch<AddressStateModel['country']['city']['address']>({\n * line1: action.line1\n * })\n * })\n * })\n * })\n * );\n * ```\n */\nexport function patch<T extends Record<string, any>>(\n patchObject: NoInfer<ɵPatchSpec<T>>\n): StateOperator<T> {\n return function patchStateOperator(existing: ExistingState<T>): T {\n let clone = null;\n for (const k in patchObject) {\n const newValue = patchObject[k];\n const existingPropValue = existing?.[k];\n const newPropValue = isStateOperator(newValue)\n ? newValue(<any>existingPropValue)\n : newValue;\n if (newPropValue !== existingPropValue) {\n if (!clone) {\n clone = { ...(<any>existing) };\n }\n clone[k] = newPropValue;\n }\n }\n return clone || existing;\n };\n}\n","import { patch, type ɵPatchSpec } from './patch';\nimport type { ExistingState, NoInfer, StateOperator } from './types';\n\n/**\n * Like `patch`, but safe to call when the state slice is `null` or\n * `undefined`. Treats a missing slice as an empty object so the patch is\n * applied against a clean baseline rather than throwing. Useful for lazily\n * initialised state properties or optional sub-states that may not have been\n * set yet.\n *\n * @example\n * ```ts\n * // Update a nested preferences slice that starts as null — no prior\n * // null-check needed; safePatch treats null as an empty object.\n * ctx.setState(\n * patch<UserStateModel>({\n * preferences: safePatch<UserPreferences>({ theme: action.theme })\n * })\n * );\n * ```\n */\nexport function safePatch<T extends object>(\n patchSpec: NoInfer<ɵPatchSpec<T>>\n): StateOperator<T> {\n const patcher = patch(patchSpec as ɵPatchSpec<T>) as unknown as StateOperator<\n Readonly<NonNullable<T>>\n >;\n return function patchSafely(existing: ExistingState<T>): T {\n return patcher(existing ?? ({} as ExistingState<Readonly<NonNullable<T>>>));\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\n\nimport { isStateOperator, isPredicate, isNumber, invalidIndex, Predicate } from './utils';\n\n/**\n * Replaces or transforms a single array element without cloning elements that\n * did not change, preserving referential equality for the rest of the array.\n * Returns the original array reference when nothing changed, keeping\n * memoized selectors and `OnPush` components from re-rendering unnecessarily.\n *\n * @param selector - The index to update, or a predicate used to locate the\n * item. Prefer a predicate when the item's position may have shifted since the\n * index was last known.\n * @param operatorOrValue - The replacement value, or a state operator applied\n * to the existing element when a derived update is needed.\n *\n * @example\n * ```ts\n * // Rename a panda — locate it by current name so the index doesn't need\n * // to be known ahead of time.\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * pandas: updateItem<string>(\n * name => name === action.payload.name,\n * action.payload.newName\n * )\n * })\n * );\n * ```\n */\nexport function updateItem<T>(\n selector: number | NoInfer<Predicate<T>>,\n operatorOrValue: NoInfer<T> | NoInfer<StateOperator<T>>\n): StateOperator<T[]> {\n return function updateItemOperator(existing: ExistingState<T[]>): T[] {\n let index = -1;\n\n if (isPredicate(selector)) {\n index = existing.findIndex(selector as Predicate<T>);\n } else if (isNumber(selector)) {\n index = selector;\n }\n\n if (invalidIndex(index)) {\n return existing as T[];\n }\n\n let value: T = null!;\n // Resolve the new value before touching the array so we can bail out\n // early and skip the clone when nothing actually changed.\n const theOperatorOrValue = operatorOrValue as T | StateOperator<T>;\n if (isStateOperator(theOperatorOrValue)) {\n value = theOperatorOrValue(existing[index] as ExistingState<T>);\n } else {\n value = theOperatorOrValue;\n }\n\n // Return the original reference to prevent memoized selectors and\n // OnPush components from reacting to a no-op update.\n if (value === existing[index]) {\n return existing as T[];\n }\n\n const clone = existing.slice();\n clone[index] = value as T;\n return clone;\n };\n}\n","import { type StateOperator, type ExistingState, type NoInfer } from './types';\nimport { isStateOperator, type Predicate } from './utils';\n\n/**\n * Replaces or transforms every array element that matches the predicate.\n * Unlike `updateItem`, which stops at the first match, this operator walks\n * the entire array so all qualifying elements are updated in one pass.\n *\n * Returns the original array reference unchanged when no elements match the\n * predicate, preserving referential equality for memoized selectors. A new\n * array is returned only when at least one element was actually updated.\n *\n * @param selector - Predicate used to decide which elements to update.\n * @param operatorOrValue - Replacement value, or a state operator applied\n * to each matching element when a derived update is needed.\n *\n * @example\n * ```ts\n * // Mark every inactive animal as active in one setState call.\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * animals: updateItems<Animal>(\n * animal => !animal.active,\n * patch({ active: true })\n * )\n * })\n * );\n * ```\n */\nexport function updateItems<T>(\n selector: NoInfer<Predicate<T>>,\n operatorOrValue: NoInfer<T> | NoInfer<StateOperator<T>>\n) {\n return function updateItemsOperator(existing: ExistingState<T[]>): T[] {\n if (!Array.isArray(existing)) {\n return [] as T[];\n } else if (existing.length === 0) {\n return existing as T[];\n }\n\n const clone = existing.slice();\n let updated = false;\n for (let index = 0; index < clone.length; index++) {\n let value = clone[index];\n if (selector(value)) {\n const theOperatorOrValue = operatorOrValue as T | StateOperator<T>;\n if (isStateOperator(theOperatorOrValue)) {\n value = theOperatorOrValue(value as ExistingState<T>);\n } else {\n value = theOperatorOrValue;\n }\n clone[index] = value;\n updated = true;\n }\n }\n // Return the original reference when nothing was updated to avoid\n // invalidating memoized selectors on a no-op call.\n return updated ? clone : existing;\n };\n}\n","import { ExistingState, NoInfer, StateOperator } from './types';\nimport { isPredicate, isNumber, invalidIndex, Predicate } from './utils';\n\n/**\n * Removes a single element from an array without mutating the original.\n * Returns the original array reference when no matching item is found, so\n * memoized selectors are not invalidated by a no-op removal.\n *\n * @param selector - The index to remove, or a predicate used to locate the\n * item. Prefer a predicate when the item's position is not guaranteed to be\n * stable across concurrent state updates.\n *\n * @example\n * ```ts\n * // Remove a panda by name — a predicate is safer than a hard-coded index\n * // because the array order may change between dispatch and execution.\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * pandas: removeItem<string>(name => name === action.payload)\n * })\n * );\n * ```\n */\nexport function removeItem<T>(selector: number | NoInfer<Predicate<T>>): StateOperator<T[]> {\n return function removeItemOperator(existing: ExistingState<T[]>): T[] {\n let index = -1;\n\n if (isPredicate(selector)) {\n index = existing.findIndex(selector);\n } else if (isNumber(selector)) {\n index = selector;\n }\n\n if (invalidIndex(index)) {\n return existing as T[];\n }\n\n const clone = existing.slice();\n clone.splice(index, 1);\n return clone;\n };\n}\n","import { type ExistingState, type NoInfer } from './types';\nimport type { Predicate } from './utils';\n\n/**\n * Removes every array element that matches the predicate. Unlike `removeItem`,\n * which stops at the first match, this operator walks the entire array so all\n * qualifying elements are eliminated in one pass.\n *\n * Returns the original array reference when no elements matched, so memoized\n * selectors are not invalidated by a no-op removal.\n *\n * @param selector - Predicate used to decide which elements to remove.\n * Elements for which the predicate returns `true` are dropped; the rest are kept.\n *\n * @example\n * ```ts\n * // Remove all inactive animals in one setState call.\n * ctx.setState(\n * patch<AnimalsStateModel>({\n * animals: removeItems<Animal>(animal => !animal.active)\n * })\n * );\n * ```\n */\nexport function removeItems<T>(selector: NoInfer<Predicate<T>>) {\n return function removeItemsOperator(existing: ExistingState<T[]>): T[] {\n if (!Array.isArray(existing)) {\n return [] as T[];\n } else if (existing.length === 0) {\n return existing as T[];\n }\n\n const newValues: T[] = [];\n for (let index = 0; index < existing.length; index++) {\n const value = existing[index];\n // Keep elements that do NOT match — the predicate describes what to remove.\n if (selector(value) === false) {\n newValues.push(value);\n }\n }\n\n // Return the original reference when nothing was removed to avoid\n // invalidating memoized selectors on a no-op call.\n // Note: checking length equality (not `newValues.length > 0`) is\n // intentional — the latter would incorrectly return `existing` when\n // all elements were removed and `newValues` is empty.\n return newValues.length === existing.length ? (existing as T[]) : newValues;\n };\n}\n","/**\n * @module\n * @description\n * Entry point for all public APIs of this package.\n */\nexport { append } from './append';\nexport { compose } from './compose';\nexport { iif } from './iif';\nexport { insertItem } from './insert-item';\nexport { patch, type ɵPatchSpec } from './patch';\nexport { safePatch } from './safe-patch';\nexport { isStateOperator, isPredicate, type Predicate } from './utils';\nexport { updateItem } from './update-item';\nexport { updateItems } from './update-items';\nexport { removeItem } from './remove-item';\nexport { removeItems } from './remove-items';\nexport type { ExistingState, NoInfer, StateOperator } from './types';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -59,6 +59,11 @@ function actionMatcher(action1) {
59
59
  * @ignore
60
60
  */
61
61
  const setValue = (obj, prop, val) => {
62
+ // Most state paths are a single segment (top-level state, no nesting).
63
+ // Skip `split`/`reduce` for that common case since it's just a shallow copy + assignment.
64
+ if (prop.indexOf('.') === -1) {
65
+ return { ...obj, [prop]: val };
66
+ }
62
67
  obj = { ...obj };
63
68
  const split = prop.split('.');
64
69
  const lastIndex = split.length - 1;
@@ -80,7 +85,11 @@ const setValue = (obj, prop, val) => {
80
85
  *
81
86
  * @ignore
82
87
  */
83
- const getValue = (obj, prop) => prop.split('.').reduce((acc, part) => acc?.[part], obj);
88
+ const getValue = (obj, prop) => {
89
+ if (prop.indexOf('.') === -1)
90
+ return obj?.[prop];
91
+ return prop.split('.').reduce((acc, part) => acc?.[part], obj);
92
+ };
84
93
 
85
94
  /**
86
95
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ngxs-store-plugins.mjs","sources":["../../../packages/store/plugins/src/actions.ts","../../../packages/store/plugins/src/symbols.ts","../../../packages/store/plugins/src/utils.ts","../../../packages/store/plugins/src/ngxs-store-plugins.ts"],"sourcesContent":["import { ɵPlainObject } from '@ngxs/store/internals';\n\n/**\n * Init action\n */\nexport class InitState {\n static readonly type = '@@INIT';\n}\n\n/**\n * Update action\n */\nexport class UpdateState {\n static readonly type = '@@UPDATE_STATE';\n\n constructor(readonly addedStates?: ɵPlainObject) {}\n}\n","import { InjectionToken, Type } from '@angular/core';\n\ndeclare const ngDevMode: boolean;\n\nexport type NgxsNextPluginFn = (state: any, action: any) => any;\n\nexport type NgxsPluginFn = (state: any, action: any, next: NgxsNextPluginFn) => any;\n\n/**\n * Plugin interface\n */\nexport interface NgxsPlugin {\n /**\n * Handle the state/action before its submitted to the state handlers.\n */\n handle(state: any, action: any, next: NgxsNextPluginFn): any;\n}\n\n/**\n * A multi-provider token used to resolve to custom NGXS plugins provided\n * at the root and feature levels through the `{provide}` scheme.\n *\n * @deprecated from v18.0.0, use `withNgxsPlugin` instead.\n */\nexport const NGXS_PLUGINS = /* @__PURE__ */ new InjectionToken<NgxsPlugin[]>(\n typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_PLUGINS' : ''\n);\n\nexport function ɵisPluginClass(\n plugin: Type<NgxsPlugin> | NgxsPluginFn\n): plugin is Type<NgxsPlugin> {\n // Determines whether the provided value is a class rather than a function.\n // If it’s a class, its handle method should be defined on its prototype,\n // as plugins can be either classes or functions.\n return !!plugin.prototype.handle;\n}\n","/**\n * Returns the type from an action instance/class.\n * @ignore\n */\nexport function getActionTypeFromInstance(action: any): string | undefined {\n return action.constructor?.type || action.type;\n}\n\n/**\n * Matches a action\n * @ignore\n */\nexport function actionMatcher(action1: any) {\n const type1 = getActionTypeFromInstance(action1);\n\n return function (action2: any) {\n return type1 === getActionTypeFromInstance(action2);\n };\n}\n\n/**\n * Set a deeply nested value. Example:\n *\n * setValue({ foo: { bar: { eat: false } } },\n * 'foo.bar.eat', true) //=> { foo: { bar: { eat: true } } }\n *\n * While it traverses it also creates new objects from top down.\n *\n * @ignore\n */\nexport const setValue = (obj: any, prop: string, val: any) => {\n obj = { ...obj };\n\n const split = prop.split('.');\n const lastIndex = split.length - 1;\n\n split.reduce((acc, part, index) => {\n if (index === lastIndex) {\n acc[part] = val;\n } else {\n acc[part] = Array.isArray(acc[part]) ? acc[part].slice() : { ...acc[part] };\n }\n\n return acc?.[part];\n }, obj);\n\n return obj;\n};\n\n/**\n * Get a deeply nested value. Example:\n *\n * getValue({ foo: bar: [] }, 'foo.bar') //=> []\n *\n * @ignore\n */\nexport const getValue = (obj: any, prop: string): any =>\n prop.split('.').reduce((acc: any, part: string) => acc?.[part], obj);\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAEA;;AAEG;MACU,SAAS,CAAA;AACpB,IAAA,OAAgB,IAAI,GAAG,QAAQ;;AAGjC;;AAEG;MACU,WAAW,CAAA;AAGD,IAAA,WAAA;AAFrB,IAAA,OAAgB,IAAI,GAAG,gBAAgB;AAEvC,IAAA,WAAA,CAAqB,WAA0B,EAAA;QAA1B,IAAW,CAAA,WAAA,GAAX,WAAW;;;;ACGlC;;;;;AAKG;AACU,MAAA,YAAY,mBAAmB,IAAI,cAAc,CAC5D,OAAO,SAAS,KAAK,WAAW,IAAI,SAAS,GAAG,cAAc,GAAG,EAAE;AAG/D,SAAU,cAAc,CAC5B,MAAuC,EAAA;;;;AAKvC,IAAA,OAAO,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM;AAClC;;ACnCA;;;AAGG;AACG,SAAU,yBAAyB,CAAC,MAAW,EAAA;IACnD,OAAO,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI;AAChD;AAEA;;;AAGG;AACG,SAAU,aAAa,CAAC,OAAY,EAAA;AACxC,IAAA,MAAM,KAAK,GAAG,yBAAyB,CAAC,OAAO,CAAC;AAEhD,IAAA,OAAO,UAAU,OAAY,EAAA;AAC3B,QAAA,OAAO,KAAK,KAAK,yBAAyB,CAAC,OAAO,CAAC;AACrD,KAAC;AACH;AAEA;;;;;;;;;AASG;AACU,MAAA,QAAQ,GAAG,CAAC,GAAQ,EAAE,IAAY,EAAE,GAAQ,KAAI;AAC3D,IAAA,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE;IAEhB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,IAAA,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC;IAElC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,KAAI;AAChC,QAAA,IAAI,KAAK,KAAK,SAAS,EAAE;AACvB,YAAA,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG;;aACV;AACL,YAAA,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE;;AAG7E,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC;KACnB,EAAE,GAAG,CAAC;AAEP,IAAA,OAAO,GAAG;AACZ;AAEA;;;;;;AAMG;AACI,MAAM,QAAQ,GAAG,CAAC,GAAQ,EAAE,IAAY,KAC7C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAQ,EAAE,IAAY,KAAK,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG;;ACzDrE;;AAEG;;;;"}
1
+ {"version":3,"file":"ngxs-store-plugins.mjs","sources":["../../../packages/store/plugins/src/actions.ts","../../../packages/store/plugins/src/symbols.ts","../../../packages/store/plugins/src/utils.ts","../../../packages/store/plugins/src/ngxs-store-plugins.ts"],"sourcesContent":["import { ɵPlainObject } from '@ngxs/store/internals';\n\n/**\n * Init action\n */\nexport class InitState {\n static readonly type = '@@INIT';\n}\n\n/**\n * Update action\n */\nexport class UpdateState {\n static readonly type = '@@UPDATE_STATE';\n\n constructor(readonly addedStates?: ɵPlainObject) {}\n}\n","import { InjectionToken, Type } from '@angular/core';\n\ndeclare const ngDevMode: boolean;\n\nexport type NgxsNextPluginFn = (state: any, action: any) => any;\n\nexport type NgxsPluginFn = (state: any, action: any, next: NgxsNextPluginFn) => any;\n\n/**\n * Plugin interface\n */\nexport interface NgxsPlugin {\n /**\n * Handle the state/action before its submitted to the state handlers.\n */\n handle(state: any, action: any, next: NgxsNextPluginFn): any;\n}\n\n/**\n * A multi-provider token used to resolve to custom NGXS plugins provided\n * at the root and feature levels through the `{provide}` scheme.\n *\n * @deprecated from v18.0.0, use `withNgxsPlugin` instead.\n */\nexport const NGXS_PLUGINS = /* @__PURE__ */ new InjectionToken<NgxsPlugin[]>(\n typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_PLUGINS' : ''\n);\n\nexport function ɵisPluginClass(\n plugin: Type<NgxsPlugin> | NgxsPluginFn\n): plugin is Type<NgxsPlugin> {\n // Determines whether the provided value is a class rather than a function.\n // If it’s a class, its handle method should be defined on its prototype,\n // as plugins can be either classes or functions.\n return !!plugin.prototype.handle;\n}\n","/**\n * Returns the type from an action instance/class.\n * @ignore\n */\nexport function getActionTypeFromInstance(action: any): string | undefined {\n return action.constructor?.type || action.type;\n}\n\n/**\n * Matches a action\n * @ignore\n */\nexport function actionMatcher(action1: any) {\n const type1 = getActionTypeFromInstance(action1);\n\n return function (action2: any) {\n return type1 === getActionTypeFromInstance(action2);\n };\n}\n\n/**\n * Set a deeply nested value. Example:\n *\n * setValue({ foo: { bar: { eat: false } } },\n * 'foo.bar.eat', true) //=> { foo: { bar: { eat: true } } }\n *\n * While it traverses it also creates new objects from top down.\n *\n * @ignore\n */\nexport const setValue = (obj: any, prop: string, val: any) => {\n // Most state paths are a single segment (top-level state, no nesting).\n // Skip `split`/`reduce` for that common case since it's just a shallow copy + assignment.\n if (prop.indexOf('.') === -1) {\n return { ...obj, [prop]: val };\n }\n\n obj = { ...obj };\n\n const split = prop.split('.');\n const lastIndex = split.length - 1;\n\n split.reduce((acc, part, index) => {\n if (index === lastIndex) {\n acc[part] = val;\n } else {\n acc[part] = Array.isArray(acc[part]) ? acc[part].slice() : { ...acc[part] };\n }\n\n return acc?.[part];\n }, obj);\n\n return obj;\n};\n\n/**\n * Get a deeply nested value. Example:\n *\n * getValue({ foo: bar: [] }, 'foo.bar') //=> []\n *\n * @ignore\n */\nexport const getValue = (obj: any, prop: string): any => {\n if (prop.indexOf('.') === -1) return obj?.[prop];\n\n return prop.split('.').reduce((acc: any, part: string) => acc?.[part], obj);\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAEA;;AAEG;MACU,SAAS,CAAA;AACpB,IAAA,OAAgB,IAAI,GAAG,QAAQ;;AAGjC;;AAEG;MACU,WAAW,CAAA;AAGD,IAAA,WAAA;AAFrB,IAAA,OAAgB,IAAI,GAAG,gBAAgB;AAEvC,IAAA,WAAA,CAAqB,WAA0B,EAAA;QAA1B,IAAA,CAAA,WAAW,GAAX,WAAW;IAAkB;;;ACGpD;;;;;AAKG;AACI,MAAM,YAAY,mBAAmB,IAAI,cAAc,CAC5D,OAAO,SAAS,KAAK,WAAW,IAAI,SAAS,GAAG,cAAc,GAAG,EAAE;AAG/D,SAAU,cAAc,CAC5B,MAAuC,EAAA;;;;AAKvC,IAAA,OAAO,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM;AAClC;;ACnCA;;;AAGG;AACG,SAAU,yBAAyB,CAAC,MAAW,EAAA;IACnD,OAAO,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI;AAChD;AAEA;;;AAGG;AACG,SAAU,aAAa,CAAC,OAAY,EAAA;AACxC,IAAA,MAAM,KAAK,GAAG,yBAAyB,CAAC,OAAO,CAAC;AAEhD,IAAA,OAAO,UAAU,OAAY,EAAA;AAC3B,QAAA,OAAO,KAAK,KAAK,yBAAyB,CAAC,OAAO,CAAC;AACrD,IAAA,CAAC;AACH;AAEA;;;;;;;;;AASG;AACI,MAAM,QAAQ,GAAG,CAAC,GAAQ,EAAE,IAAY,EAAE,GAAQ,KAAI;;;IAG3D,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;QAC5B,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,GAAG,EAAE;IAChC;AAEA,IAAA,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE;IAEhB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,IAAA,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC;IAElC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,KAAI;AAChC,QAAA,IAAI,KAAK,KAAK,SAAS,EAAE;AACvB,YAAA,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG;QACjB;aAAO;AACL,YAAA,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE;QAC7E;AAEA,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC;IACpB,CAAC,EAAE,GAAG,CAAC;AAEP,IAAA,OAAO,GAAG;AACZ;AAEA;;;;;;AAMG;MACU,QAAQ,GAAG,CAAC,GAAQ,EAAE,IAAY,KAAS;IACtD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAAE,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC;IAEhD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAQ,EAAE,IAAY,KAAK,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAC7E;;AClEA;;AAEG;;;;"}