@angular/forms 21.1.0-next.0 → 21.1.0-next.2

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.
@@ -1,34 +1,28 @@
1
1
  /**
2
- * @license Angular v21.1.0-next.0
2
+ * @license Angular v21.1.0-next.2
3
3
  * (c) 2010-2025 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6
 
7
- import { computed, untracked, runInInjectionContext, linkedSignal, Injector, signal, APP_ID, effect, inject } from '@angular/core';
7
+ import { untracked, computed, runInInjectionContext, Injector, linkedSignal, signal, APP_ID, effect, inject } from '@angular/core';
8
8
  import { AbstractControl } from '@angular/forms';
9
9
  import { SIGNAL } from '@angular/core/primitives/signals';
10
10
 
11
- function isArray(value) {
12
- return Array.isArray(value);
13
- }
14
- function isObject(value) {
15
- return (typeof value === 'object' || typeof value === 'function') && value != null;
11
+ let boundPathDepth = 0;
12
+ function getBoundPathDepth() {
13
+ return boundPathDepth;
16
14
  }
17
-
18
- function reduceChildren(node, initialValue, fn, shortCircuit) {
19
- const childrenMap = node.structure.childrenMap();
20
- if (!childrenMap) {
21
- return initialValue;
22
- }
23
- let value = initialValue;
24
- for (const child of childrenMap.values()) {
25
- if (shortCircuit?.(value)) {
26
- break;
15
+ function setBoundPathDepthForResolution(fn, depth) {
16
+ return (...args) => {
17
+ try {
18
+ boundPathDepth = depth;
19
+ return fn(...args);
20
+ } finally {
21
+ boundPathDepth = 0;
27
22
  }
28
- value = fn(child, value);
29
- }
30
- return value;
23
+ };
31
24
  }
25
+
32
26
  function shortCircuitFalse(value) {
33
27
  return !value;
34
28
  }
@@ -42,157 +36,11 @@ function getInjectorFromOptions(options) {
42
36
  return options.parent.structure.root.structure.injector;
43
37
  }
44
38
 
45
- function calculateValidationSelfStatus(state) {
46
- if (state.errors().length > 0) {
47
- return 'invalid';
48
- }
49
- if (state.pending()) {
50
- return 'unknown';
51
- }
52
- return 'valid';
53
- }
54
- class FieldValidationState {
55
- node;
56
- constructor(node) {
57
- this.node = node;
58
- }
59
- rawSyncTreeErrors = computed(() => {
60
- if (this.shouldSkipValidation()) {
61
- return [];
62
- }
63
- return [...this.node.logicNode.logic.syncTreeErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawSyncTreeErrors() ?? [])];
64
- }, {
65
- ...(ngDevMode ? {
66
- debugName: "rawSyncTreeErrors"
67
- } : {})
68
- });
69
- syncErrors = computed(() => {
70
- if (this.shouldSkipValidation()) {
71
- return [];
72
- }
73
- return [...this.node.logicNode.logic.syncErrors.compute(this.node.context), ...this.syncTreeErrors(), ...normalizeErrors(this.node.submitState.serverErrors())];
74
- }, {
75
- ...(ngDevMode ? {
76
- debugName: "syncErrors"
77
- } : {})
78
- });
79
- syncValid = computed(() => {
80
- if (this.shouldSkipValidation()) {
81
- return true;
82
- }
83
- return reduceChildren(this.node, this.syncErrors().length === 0, (child, value) => value && child.validationState.syncValid(), shortCircuitFalse);
84
- }, {
85
- ...(ngDevMode ? {
86
- debugName: "syncValid"
87
- } : {})
88
- });
89
- syncTreeErrors = computed(() => this.rawSyncTreeErrors().filter(err => err.field === this.node.fieldProxy), {
90
- ...(ngDevMode ? {
91
- debugName: "syncTreeErrors"
92
- } : {})
93
- });
94
- rawAsyncErrors = computed(() => {
95
- if (this.shouldSkipValidation()) {
96
- return [];
97
- }
98
- return [...this.node.logicNode.logic.asyncErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawAsyncErrors() ?? [])];
99
- }, {
100
- ...(ngDevMode ? {
101
- debugName: "rawAsyncErrors"
102
- } : {})
103
- });
104
- asyncErrors = computed(() => {
105
- if (this.shouldSkipValidation()) {
106
- return [];
107
- }
108
- return this.rawAsyncErrors().filter(err => err === 'pending' || err.field === this.node.fieldProxy);
109
- }, {
110
- ...(ngDevMode ? {
111
- debugName: "asyncErrors"
112
- } : {})
113
- });
114
- errors = computed(() => [...this.syncErrors(), ...this.asyncErrors().filter(err => err !== 'pending')], {
115
- ...(ngDevMode ? {
116
- debugName: "errors"
117
- } : {})
118
- });
119
- errorSummary = computed(() => reduceChildren(this.node, this.errors(), (child, result) => [...result, ...child.errorSummary()]), {
120
- ...(ngDevMode ? {
121
- debugName: "errorSummary"
122
- } : {})
123
- });
124
- pending = computed(() => reduceChildren(this.node, this.asyncErrors().includes('pending'), (child, value) => value || child.validationState.asyncErrors().includes('pending')), {
125
- ...(ngDevMode ? {
126
- debugName: "pending"
127
- } : {})
128
- });
129
- status = computed(() => {
130
- if (this.shouldSkipValidation()) {
131
- return 'valid';
132
- }
133
- let ownStatus = calculateValidationSelfStatus(this);
134
- return reduceChildren(this.node, ownStatus, (child, value) => {
135
- if (value === 'invalid' || child.validationState.status() === 'invalid') {
136
- return 'invalid';
137
- } else if (value === 'unknown' || child.validationState.status() === 'unknown') {
138
- return 'unknown';
139
- }
140
- return 'valid';
141
- }, v => v === 'invalid');
142
- }, {
143
- ...(ngDevMode ? {
144
- debugName: "status"
145
- } : {})
146
- });
147
- valid = computed(() => this.status() === 'valid', {
148
- ...(ngDevMode ? {
149
- debugName: "valid"
150
- } : {})
151
- });
152
- invalid = computed(() => this.status() === 'invalid', {
153
- ...(ngDevMode ? {
154
- debugName: "invalid"
155
- } : {})
156
- });
157
- shouldSkipValidation = computed(() => this.node.hidden() || this.node.disabled() || this.node.readonly(), {
158
- ...(ngDevMode ? {
159
- debugName: "shouldSkipValidation"
160
- } : {})
161
- });
162
- }
163
- function normalizeErrors(error) {
164
- if (error === undefined) {
165
- return [];
166
- }
167
- if (isArray(error)) {
168
- return error;
169
- }
170
- return [error];
171
- }
172
- function addDefaultField(errors, field) {
173
- if (isArray(errors)) {
174
- for (const error of errors) {
175
- error.field ??= field;
176
- }
177
- } else if (errors) {
178
- errors.field ??= field;
179
- }
180
- return errors;
181
- }
182
-
183
- let boundPathDepth = 0;
184
- function getBoundPathDepth() {
185
- return boundPathDepth;
39
+ function isArray(value) {
40
+ return Array.isArray(value);
186
41
  }
187
- function setBoundPathDepthForResolution(fn, depth) {
188
- return (...args) => {
189
- try {
190
- boundPathDepth = depth;
191
- return fn(...args);
192
- } finally {
193
- boundPathDepth = 0;
194
- }
195
- };
42
+ function isObject(value) {
43
+ return (typeof value === 'object' || typeof value === 'function') && value != null;
196
44
  }
197
45
 
198
46
  const DYNAMIC = Symbol();
@@ -255,10 +103,10 @@ class ArrayMergeLogic extends ArrayMergeIgnoreLogic {
255
103
  super(predicates, undefined);
256
104
  }
257
105
  }
258
- class AggregateMetadataMergeLogic extends AbstractLogic {
106
+ class MetadataMergeLogic extends AbstractLogic {
259
107
  key;
260
108
  get defaultValue() {
261
- return this.key.getInitial();
109
+ return this.key.reducer.getInitial();
262
110
  }
263
111
  constructor(predicates, key) {
264
112
  super(predicates);
@@ -266,13 +114,13 @@ class AggregateMetadataMergeLogic extends AbstractLogic {
266
114
  }
267
115
  compute(ctx) {
268
116
  if (this.fns.length === 0) {
269
- return this.key.getInitial();
117
+ return this.key.reducer.getInitial();
270
118
  }
271
- let acc = this.key.getInitial();
119
+ let acc = this.key.reducer.getInitial();
272
120
  for (let i = 0; i < this.fns.length; i++) {
273
121
  const item = this.fns[i](ctx);
274
122
  if (item !== IGNORED) {
275
- acc = this.key.reduce(acc, item);
123
+ acc = this.key.reducer.reduce(acc, item);
276
124
  }
277
125
  }
278
126
  return acc;
@@ -304,8 +152,7 @@ class LogicContainer {
304
152
  syncErrors;
305
153
  syncTreeErrors;
306
154
  asyncErrors;
307
- aggregateMetadataKeys = new Map();
308
- metadataFactories = new Map();
155
+ metadata = new Map();
309
156
  constructor(predicates) {
310
157
  this.predicates = predicates;
311
158
  this.hidden = new BooleanOrLogic(predicates);
@@ -315,26 +162,17 @@ class LogicContainer {
315
162
  this.syncTreeErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
316
163
  this.asyncErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
317
164
  }
318
- hasAggregateMetadata(key) {
319
- return this.aggregateMetadataKeys.has(key);
320
- }
321
- getAggregateMetadataEntries() {
322
- return this.aggregateMetadataKeys.entries();
165
+ hasMetadata(key) {
166
+ return this.metadata.has(key);
323
167
  }
324
- getMetadataFactoryEntries() {
325
- return this.metadataFactories.entries();
168
+ getMetadataKeys() {
169
+ return this.metadata.keys();
326
170
  }
327
- getAggregateMetadata(key) {
328
- if (!this.aggregateMetadataKeys.has(key)) {
329
- this.aggregateMetadataKeys.set(key, new AggregateMetadataMergeLogic(this.predicates, key));
330
- }
331
- return this.aggregateMetadataKeys.get(key);
332
- }
333
- addMetadataFactory(key, factory) {
334
- if (this.metadataFactories.has(key)) {
335
- throw new Error(`Can't define value twice for the same MetadataKey`);
171
+ getMetadata(key) {
172
+ if (!this.metadata.has(key)) {
173
+ this.metadata.set(key, new MetadataMergeLogic(this.predicates, key));
336
174
  }
337
- this.metadataFactories.set(key, factory);
175
+ return this.metadata.get(key);
338
176
  }
339
177
  mergeIn(other) {
340
178
  this.hidden.mergeIn(other.hidden);
@@ -343,11 +181,9 @@ class LogicContainer {
343
181
  this.syncErrors.mergeIn(other.syncErrors);
344
182
  this.syncTreeErrors.mergeIn(other.syncTreeErrors);
345
183
  this.asyncErrors.mergeIn(other.asyncErrors);
346
- for (const [key, metadataLogic] of other.getAggregateMetadataEntries()) {
347
- this.getAggregateMetadata(key).mergeIn(metadataLogic);
348
- }
349
- for (const [key, metadataFactory] of other.getMetadataFactoryEntries()) {
350
- this.addMetadataFactory(key, metadataFactory);
184
+ for (const key of other.getMetadataKeys()) {
185
+ const metadataLogic = other.metadata.get(key);
186
+ this.getMetadata(key).mergeIn(metadataLogic);
351
187
  }
352
188
  }
353
189
  }
@@ -385,11 +221,8 @@ class LogicNodeBuilder extends AbstractLogicNodeBuilder {
385
221
  addAsyncErrorRule(logic) {
386
222
  this.getCurrent().addAsyncErrorRule(logic);
387
223
  }
388
- addAggregateMetadataRule(key, logic) {
389
- this.getCurrent().addAggregateMetadataRule(key, logic);
390
- }
391
- addMetadataFactory(key, factory) {
392
- this.getCurrent().addMetadataFactory(key, factory);
224
+ addMetadataRule(key, logic) {
225
+ this.getCurrent().addMetadataRule(key, logic);
393
226
  }
394
227
  getChild(key) {
395
228
  if (key === DYNAMIC) {
@@ -461,11 +294,8 @@ class NonMergeableLogicNodeBuilder extends AbstractLogicNodeBuilder {
461
294
  addAsyncErrorRule(logic) {
462
295
  this.logic.asyncErrors.push(setBoundPathDepthForResolution(logic, this.depth));
463
296
  }
464
- addAggregateMetadataRule(key, logic) {
465
- this.logic.getAggregateMetadata(key).push(setBoundPathDepthForResolution(logic, this.depth));
466
- }
467
- addMetadataFactory(key, factory) {
468
- this.logic.addMetadataFactory(key, setBoundPathDepthForResolution(factory, this.depth));
297
+ addMetadataRule(key, logic) {
298
+ this.logic.getMetadata(key).push(setBoundPathDepthForResolution(logic, this.depth));
469
299
  }
470
300
  getChild(key) {
471
301
  if (!this.children.has(key)) {
@@ -683,64 +513,196 @@ function assertPathIsCurrent(path) {
683
513
  }
684
514
  }
685
515
 
686
- class MetadataKey {
687
- brand;
688
- constructor() {}
516
+ function metadata(path, key, logic) {
517
+ assertPathIsCurrent(path);
518
+ const pathNode = FieldPathNode.unwrapFieldPath(path);
519
+ pathNode.builder.addMetadataRule(key, logic);
520
+ return key;
689
521
  }
690
- function createMetadataKey() {
691
- return new MetadataKey();
522
+ const MetadataReducer = {
523
+ list() {
524
+ return {
525
+ reduce: (acc, item) => item === undefined ? acc : [...acc, item],
526
+ getInitial: () => []
527
+ };
528
+ },
529
+ min() {
530
+ return {
531
+ reduce: (acc, item) => {
532
+ if (acc === undefined || item === undefined) {
533
+ return acc ?? item;
534
+ }
535
+ return Math.min(acc, item);
536
+ },
537
+ getInitial: () => undefined
538
+ };
539
+ },
540
+ max() {
541
+ return {
542
+ reduce: (prev, next) => {
543
+ if (prev === undefined || next === undefined) {
544
+ return prev ?? next;
545
+ }
546
+ return Math.max(prev, next);
547
+ },
548
+ getInitial: () => undefined
549
+ };
550
+ },
551
+ or() {
552
+ return {
553
+ reduce: (prev, next) => prev || next,
554
+ getInitial: () => false
555
+ };
556
+ },
557
+ and() {
558
+ return {
559
+ reduce: (prev, next) => prev && next,
560
+ getInitial: () => true
561
+ };
562
+ },
563
+ override
564
+ };
565
+ function override(getInitial) {
566
+ return {
567
+ reduce: (_, item) => item,
568
+ getInitial: () => getInitial?.()
569
+ };
692
570
  }
693
- class AggregateMetadataKey {
694
- reduce;
695
- getInitial;
571
+ class MetadataKey {
572
+ reducer;
573
+ create;
696
574
  brand;
697
- constructor(reduce, getInitial) {
698
- this.reduce = reduce;
699
- this.getInitial = getInitial;
575
+ constructor(reducer, create) {
576
+ this.reducer = reducer;
577
+ this.create = create;
700
578
  }
701
579
  }
702
- function reducedMetadataKey(reduce, getInitial) {
703
- return new AggregateMetadataKey(reduce, getInitial);
580
+ function createMetadataKey(reducer) {
581
+ return new MetadataKey(reducer ?? MetadataReducer.override());
582
+ }
583
+ function createManagedMetadataKey(create, reducer) {
584
+ return new MetadataKey(reducer ?? MetadataReducer.override(), create);
704
585
  }
705
- function listMetadataKey() {
706
- return reducedMetadataKey((acc, item) => item === undefined ? acc : [...acc, item], () => []);
586
+ const REQUIRED = createMetadataKey(MetadataReducer.or());
587
+ const MIN = createMetadataKey(MetadataReducer.max());
588
+ const MAX = createMetadataKey(MetadataReducer.min());
589
+ const MIN_LENGTH = createMetadataKey(MetadataReducer.max());
590
+ const MAX_LENGTH = createMetadataKey(MetadataReducer.min());
591
+ const PATTERN = createMetadataKey(MetadataReducer.list());
592
+
593
+ function calculateValidationSelfStatus(state) {
594
+ if (state.errors().length > 0) {
595
+ return 'invalid';
596
+ }
597
+ if (state.pending()) {
598
+ return 'unknown';
599
+ }
600
+ return 'valid';
707
601
  }
708
- function minMetadataKey() {
709
- return reducedMetadataKey((prev, next) => {
710
- if (prev === undefined) {
711
- return next;
602
+ class FieldValidationState {
603
+ node;
604
+ constructor(node) {
605
+ this.node = node;
606
+ }
607
+ rawSyncTreeErrors = computed(() => {
608
+ if (this.shouldSkipValidation()) {
609
+ return [];
610
+ }
611
+ return [...this.node.logicNode.logic.syncTreeErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawSyncTreeErrors() ?? [])];
612
+ }, ...(ngDevMode ? [{
613
+ debugName: "rawSyncTreeErrors"
614
+ }] : []));
615
+ syncErrors = computed(() => {
616
+ if (this.shouldSkipValidation()) {
617
+ return [];
618
+ }
619
+ return [...this.node.logicNode.logic.syncErrors.compute(this.node.context), ...this.syncTreeErrors(), ...normalizeErrors(this.node.submitState.serverErrors())];
620
+ }, ...(ngDevMode ? [{
621
+ debugName: "syncErrors"
622
+ }] : []));
623
+ syncValid = computed(() => {
624
+ if (this.shouldSkipValidation()) {
625
+ return true;
712
626
  }
713
- if (next === undefined) {
714
- return prev;
627
+ return this.node.structure.reduceChildren(this.syncErrors().length === 0, (child, value) => value && child.validationState.syncValid(), shortCircuitFalse);
628
+ }, ...(ngDevMode ? [{
629
+ debugName: "syncValid"
630
+ }] : []));
631
+ syncTreeErrors = computed(() => this.rawSyncTreeErrors().filter(err => err.field === this.node.fieldProxy), ...(ngDevMode ? [{
632
+ debugName: "syncTreeErrors"
633
+ }] : []));
634
+ rawAsyncErrors = computed(() => {
635
+ if (this.shouldSkipValidation()) {
636
+ return [];
715
637
  }
716
- return Math.min(prev, next);
717
- }, () => undefined);
718
- }
719
- function maxMetadataKey() {
720
- return reducedMetadataKey((prev, next) => {
721
- if (prev === undefined) {
722
- return next;
638
+ return [...this.node.logicNode.logic.asyncErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawAsyncErrors() ?? [])];
639
+ }, ...(ngDevMode ? [{
640
+ debugName: "rawAsyncErrors"
641
+ }] : []));
642
+ asyncErrors = computed(() => {
643
+ if (this.shouldSkipValidation()) {
644
+ return [];
723
645
  }
724
- if (next === undefined) {
725
- return prev;
646
+ return this.rawAsyncErrors().filter(err => err === 'pending' || err.field === this.node.fieldProxy);
647
+ }, ...(ngDevMode ? [{
648
+ debugName: "asyncErrors"
649
+ }] : []));
650
+ errors = computed(() => [...this.syncErrors(), ...this.asyncErrors().filter(err => err !== 'pending')], ...(ngDevMode ? [{
651
+ debugName: "errors"
652
+ }] : []));
653
+ errorSummary = computed(() => this.node.structure.reduceChildren(this.errors(), (child, result) => [...result, ...child.errorSummary()]), ...(ngDevMode ? [{
654
+ debugName: "errorSummary"
655
+ }] : []));
656
+ pending = computed(() => this.node.structure.reduceChildren(this.asyncErrors().includes('pending'), (child, value) => value || child.validationState.asyncErrors().includes('pending')), ...(ngDevMode ? [{
657
+ debugName: "pending"
658
+ }] : []));
659
+ status = computed(() => {
660
+ if (this.shouldSkipValidation()) {
661
+ return 'valid';
726
662
  }
727
- return Math.max(prev, next);
728
- }, () => undefined);
663
+ let ownStatus = calculateValidationSelfStatus(this);
664
+ return this.node.structure.reduceChildren(ownStatus, (child, value) => {
665
+ if (value === 'invalid' || child.validationState.status() === 'invalid') {
666
+ return 'invalid';
667
+ } else if (value === 'unknown' || child.validationState.status() === 'unknown') {
668
+ return 'unknown';
669
+ }
670
+ return 'valid';
671
+ }, v => v === 'invalid');
672
+ }, ...(ngDevMode ? [{
673
+ debugName: "status"
674
+ }] : []));
675
+ valid = computed(() => this.status() === 'valid', ...(ngDevMode ? [{
676
+ debugName: "valid"
677
+ }] : []));
678
+ invalid = computed(() => this.status() === 'invalid', ...(ngDevMode ? [{
679
+ debugName: "invalid"
680
+ }] : []));
681
+ shouldSkipValidation = computed(() => this.node.hidden() || this.node.disabled() || this.node.readonly(), ...(ngDevMode ? [{
682
+ debugName: "shouldSkipValidation"
683
+ }] : []));
729
684
  }
730
- function orMetadataKey() {
731
- return reducedMetadataKey((prev, next) => prev || next, () => false);
685
+ function normalizeErrors(error) {
686
+ if (error === undefined) {
687
+ return [];
688
+ }
689
+ if (isArray(error)) {
690
+ return error;
691
+ }
692
+ return [error];
732
693
  }
733
- function andMetadataKey() {
734
- return reducedMetadataKey((prev, next) => prev && next, () => true);
694
+ function addDefaultField(errors, field) {
695
+ if (isArray(errors)) {
696
+ for (const error of errors) {
697
+ error.field ??= field;
698
+ }
699
+ } else if (errors) {
700
+ errors.field ??= field;
701
+ }
702
+ return errors;
735
703
  }
736
- const REQUIRED = orMetadataKey();
737
- const MIN = maxMetadataKey();
738
- const MAX = minMetadataKey();
739
- const MIN_LENGTH = maxMetadataKey();
740
- const MAX_LENGTH = minMetadataKey();
741
- const PATTERN = listMetadataKey();
742
704
 
743
- const DEBOUNCER = reducedMetadataKey((_, item) => item, () => undefined);
705
+ const DEBOUNCER = createMetadataKey();
744
706
 
745
707
  class FieldNodeContext {
746
708
  node;
@@ -768,11 +730,9 @@ class FieldNodeContext {
768
730
  }
769
731
  }
770
732
  return field.fieldProxy;
771
- }, {
772
- ...(ngDevMode ? {
773
- debugName: "resolver"
774
- } : {})
775
- });
733
+ }, ...(ngDevMode ? [{
734
+ debugName: "resolver"
735
+ }] : []));
776
736
  this.cache.set(target, resolver);
777
737
  }
778
738
  return this.cache.get(target)();
@@ -798,11 +758,9 @@ class FieldNodeContext {
798
758
  throw new Error(`RuntimeError: cannot access index, parent field is not an array`);
799
759
  }
800
760
  return Number(key);
801
- }, {
802
- ...(ngDevMode ? {
803
- debugName: "index"
804
- } : {})
805
- });
761
+ }, ...(ngDevMode ? [{
762
+ debugName: "index"
763
+ }] : []));
806
764
  fieldTreeOf = p => this.resolve(p);
807
765
  stateOf = p => this.resolve(p)();
808
766
  valueOf = p => {
@@ -819,33 +777,28 @@ class FieldMetadataState {
819
777
  metadata = new Map();
820
778
  constructor(node) {
821
779
  this.node = node;
822
- untracked(() => runInInjectionContext(this.node.structure.injector, () => {
823
- for (const [key, factory] of this.node.logicNode.logic.getMetadataFactoryEntries()) {
824
- this.metadata.set(key, factory(this.node.context));
780
+ for (const key of this.node.logicNode.logic.getMetadataKeys()) {
781
+ if (key.create) {
782
+ const logic = this.node.logicNode.logic.getMetadata(key);
783
+ const result = untracked(() => runInInjectionContext(this.node.structure.injector, () => key.create(computed(() => logic.compute(this.node.context)))));
784
+ this.metadata.set(key, result);
825
785
  }
826
- }));
786
+ }
827
787
  }
828
788
  get(key) {
829
- if (key instanceof MetadataKey) {
830
- return this.metadata.get(key);
831
- }
832
- if (!this.metadata.has(key)) {
833
- const logic = this.node.logicNode.logic.getAggregateMetadata(key);
834
- const result = computed(() => logic.compute(this.node.context), {
835
- ...(ngDevMode ? {
836
- debugName: "result"
837
- } : {})
838
- });
839
- this.metadata.set(key, result);
789
+ if (this.has(key)) {
790
+ if (!this.metadata.has(key)) {
791
+ if (key.create) {
792
+ throw Error('Managed metadata cannot be created lazily');
793
+ }
794
+ const logic = this.node.logicNode.logic.getMetadata(key);
795
+ this.metadata.set(key, computed(() => logic.compute(this.node.context)));
796
+ }
840
797
  }
841
798
  return this.metadata.get(key);
842
799
  }
843
800
  has(key) {
844
- if (key instanceof AggregateMetadataKey) {
845
- return this.node.logicNode.logic.hasAggregateMetadata(key);
846
- } else {
847
- return this.metadata.has(key);
848
- }
801
+ return this.node.logicNode.logic.hasMetadata(key);
849
802
  }
850
803
  }
851
804
 
@@ -862,7 +815,10 @@ const FIELD_PROXY_HANDLER = {
862
815
  return tgt.value().length;
863
816
  }
864
817
  if (p === Symbol.iterator) {
865
- return Array.prototype[p];
818
+ return () => {
819
+ tgt.value();
820
+ return Array.prototype[Symbol.iterator].apply(tgt.fieldProxy);
821
+ };
866
822
  }
867
823
  }
868
824
  if (isObject(value)) {
@@ -917,6 +873,8 @@ function valueForWrite(sourceValue, newPropValue, prop) {
917
873
 
918
874
  class FieldNodeStructure {
919
875
  logic;
876
+ node;
877
+ createChildNode;
920
878
  identitySymbol = Symbol();
921
879
  _injector = undefined;
922
880
  get injector() {
@@ -926,32 +884,146 @@ class FieldNodeStructure {
926
884
  });
927
885
  return this._injector;
928
886
  }
929
- constructor(logic) {
887
+ constructor(logic, node, createChildNode) {
930
888
  this.logic = logic;
889
+ this.node = node;
890
+ this.createChildNode = createChildNode;
931
891
  }
932
892
  children() {
933
- return this.childrenMap()?.values() ?? [];
893
+ const map = this.childrenMap();
894
+ if (map === undefined) {
895
+ return [];
896
+ }
897
+ return Array.from(map.byPropertyKey.values()).map(child => untracked(child.reader));
934
898
  }
935
899
  getChild(key) {
900
+ const strKey = key.toString();
901
+ let reader = untracked(this.childrenMap)?.byPropertyKey.get(strKey)?.reader;
902
+ if (!reader) {
903
+ reader = this.createReader(strKey);
904
+ }
905
+ return reader();
906
+ }
907
+ reduceChildren(initialValue, fn, shortCircuit) {
936
908
  const map = this.childrenMap();
937
- const value = this.value();
938
- if (!map || !isObject(value)) {
939
- return undefined;
909
+ if (!map) {
910
+ return initialValue;
940
911
  }
941
- if (isArray(value)) {
942
- const childValue = value[key];
943
- if (isObject(childValue) && childValue.hasOwnProperty(this.identitySymbol)) {
944
- key = childValue[this.identitySymbol];
912
+ let value = initialValue;
913
+ for (const child of map.byPropertyKey.values()) {
914
+ if (shortCircuit?.(value)) {
915
+ break;
945
916
  }
917
+ value = fn(untracked(child.reader), value);
946
918
  }
947
- return map.get(typeof key === 'number' ? key.toString() : key);
919
+ return value;
948
920
  }
949
921
  destroy() {
950
922
  this.injector.destroy();
951
923
  }
924
+ createKeyInParent(options, identityInParent, initialKeyInParent) {
925
+ if (options.kind === 'root') {
926
+ return ROOT_KEY_IN_PARENT;
927
+ }
928
+ if (identityInParent === undefined) {
929
+ const key = initialKeyInParent;
930
+ return computed(() => {
931
+ if (this.parent.structure.getChild(key) !== this.node) {
932
+ throw new Error(`RuntimeError: orphan field, looking for property '${key}' of ${getDebugName(this.parent)}`);
933
+ }
934
+ return key;
935
+ });
936
+ } else {
937
+ let lastKnownKey = initialKeyInParent;
938
+ return computed(() => {
939
+ const parentValue = this.parent.structure.value();
940
+ if (!isArray(parentValue)) {
941
+ throw new Error(`RuntimeError: orphan field, expected ${getDebugName(this.parent)} to be an array`);
942
+ }
943
+ const data = parentValue[lastKnownKey];
944
+ if (isObject(data) && data.hasOwnProperty(this.parent.structure.identitySymbol) && data[this.parent.structure.identitySymbol] === identityInParent) {
945
+ return lastKnownKey;
946
+ }
947
+ for (let i = 0; i < parentValue.length; i++) {
948
+ const data = parentValue[i];
949
+ if (isObject(data) && data.hasOwnProperty(this.parent.structure.identitySymbol) && data[this.parent.structure.identitySymbol] === identityInParent) {
950
+ return lastKnownKey = i.toString();
951
+ }
952
+ }
953
+ throw new Error(`RuntimeError: orphan field, can't find element in array ${getDebugName(this.parent)}`);
954
+ });
955
+ }
956
+ }
957
+ createChildrenMap() {
958
+ return linkedSignal({
959
+ source: this.value,
960
+ computation: (value, previous) => {
961
+ if (!isObject(value)) {
962
+ return undefined;
963
+ }
964
+ const prevData = previous?.value ?? {
965
+ byPropertyKey: new Map()
966
+ };
967
+ let data;
968
+ const parentIsArray = isArray(value);
969
+ if (prevData !== undefined) {
970
+ if (parentIsArray) {
971
+ data = maybeRemoveStaleArrayFields(prevData, value, this.identitySymbol);
972
+ } else {
973
+ data = maybeRemoveStaleObjectFields(prevData, value);
974
+ }
975
+ }
976
+ for (const key of Object.keys(value)) {
977
+ let trackingKey = undefined;
978
+ const childValue = value[key];
979
+ if (childValue === undefined) {
980
+ if (prevData.byPropertyKey.has(key)) {
981
+ data ??= {
982
+ ...prevData
983
+ };
984
+ data.byPropertyKey.delete(key);
985
+ }
986
+ continue;
987
+ }
988
+ if (parentIsArray && isObject(childValue) && !isArray(childValue)) {
989
+ trackingKey = childValue[this.identitySymbol] ??= Symbol(ngDevMode ? `id:${globalId++}` : '');
990
+ }
991
+ let childNode;
992
+ if (trackingKey) {
993
+ if (!prevData.byTrackingKey?.has(trackingKey)) {
994
+ data ??= {
995
+ ...prevData
996
+ };
997
+ data.byTrackingKey ??= new Map();
998
+ data.byTrackingKey.set(trackingKey, this.createChildNode(key, trackingKey, parentIsArray));
999
+ }
1000
+ childNode = (data ?? prevData).byTrackingKey.get(trackingKey);
1001
+ }
1002
+ const child = prevData.byPropertyKey.get(key);
1003
+ if (child === undefined) {
1004
+ data ??= {
1005
+ ...prevData
1006
+ };
1007
+ data.byPropertyKey.set(key, {
1008
+ reader: this.createReader(key),
1009
+ node: childNode ?? this.createChildNode(key, trackingKey, parentIsArray)
1010
+ });
1011
+ } else if (childNode && childNode !== child.node) {
1012
+ data ??= {
1013
+ ...prevData
1014
+ };
1015
+ child.node = childNode;
1016
+ }
1017
+ }
1018
+ return data ?? prevData;
1019
+ }
1020
+ });
1021
+ }
1022
+ createReader(key) {
1023
+ return computed(() => this.childrenMap()?.byPropertyKey.get(key)?.node);
1024
+ }
952
1025
  }
953
1026
  class RootFieldNodeStructure extends FieldNodeStructure {
954
- node;
955
1027
  fieldManager;
956
1028
  value;
957
1029
  get parent() {
@@ -967,15 +1039,15 @@ class RootFieldNodeStructure extends FieldNodeStructure {
967
1039
  return ROOT_KEY_IN_PARENT;
968
1040
  }
969
1041
  childrenMap;
970
- constructor(node, pathNode, logic, fieldManager, value, adapter, createChildNode) {
971
- super(logic);
972
- this.node = node;
1042
+ constructor(node, logic, fieldManager, value, createChildNode) {
1043
+ super(logic, node, createChildNode);
973
1044
  this.fieldManager = fieldManager;
974
1045
  this.value = value;
975
- this.childrenMap = makeChildrenMapSignal(node, value, this.identitySymbol, pathNode, logic, adapter, createChildNode);
1046
+ this.childrenMap = this.createChildrenMap();
976
1047
  }
977
1048
  }
978
1049
  class ChildFieldNodeStructure extends FieldNodeStructure {
1050
+ logic;
979
1051
  parent;
980
1052
  root;
981
1053
  pathKeys;
@@ -985,151 +1057,87 @@ class ChildFieldNodeStructure extends FieldNodeStructure {
985
1057
  get fieldManager() {
986
1058
  return this.root.structure.fieldManager;
987
1059
  }
988
- constructor(node, pathNode, logic, parent, identityInParent, initialKeyInParent, adapter, createChildNode) {
989
- super(logic);
1060
+ constructor(node, logic, parent, identityInParent, initialKeyInParent, createChildNode) {
1061
+ super(logic, node, createChildNode);
1062
+ this.logic = logic;
990
1063
  this.parent = parent;
991
1064
  this.root = this.parent.structure.root;
992
- this.pathKeys = computed(() => [...parent.structure.pathKeys(), this.keyInParent()], {
993
- ...(ngDevMode ? {
994
- debugName: "pathKeys"
995
- } : {})
996
- });
997
- if (identityInParent === undefined) {
998
- const key = initialKeyInParent;
999
- this.keyInParent = computed(() => {
1000
- if (parent.structure.childrenMap()?.get(key) !== node) {
1001
- throw new Error(`RuntimeError: orphan field, looking for property '${key}' of ${getDebugName(parent)}`);
1002
- }
1003
- return key;
1004
- }, {
1005
- ...(ngDevMode ? {
1006
- debugName: "keyInParent"
1007
- } : {})
1008
- });
1009
- } else {
1010
- let lastKnownKey = initialKeyInParent;
1011
- this.keyInParent = computed(() => {
1012
- const parentValue = parent.structure.value();
1013
- if (!isArray(parentValue)) {
1014
- throw new Error(`RuntimeError: orphan field, expected ${getDebugName(parent)} to be an array`);
1015
- }
1016
- const data = parentValue[lastKnownKey];
1017
- if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
1018
- return lastKnownKey;
1019
- }
1020
- for (let i = 0; i < parentValue.length; i++) {
1021
- const data = parentValue[i];
1022
- if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
1023
- return lastKnownKey = i.toString();
1024
- }
1025
- }
1026
- throw new Error(`RuntimeError: orphan field, can't find element in array ${getDebugName(parent)}`);
1027
- }, {
1028
- ...(ngDevMode ? {
1029
- debugName: "keyInParent"
1030
- } : {})
1031
- });
1032
- }
1065
+ this.keyInParent = this.createKeyInParent({
1066
+ kind: 'child',
1067
+ parent,
1068
+ pathNode: undefined,
1069
+ logic,
1070
+ initialKeyInParent,
1071
+ identityInParent,
1072
+ fieldAdapter: undefined
1073
+ }, identityInParent, initialKeyInParent);
1074
+ this.pathKeys = computed(() => [...parent.structure.pathKeys(), this.keyInParent()], ...(ngDevMode ? [{
1075
+ debugName: "pathKeys"
1076
+ }] : []));
1033
1077
  this.value = deepSignal(this.parent.structure.value, this.keyInParent);
1034
- this.childrenMap = makeChildrenMapSignal(node, this.value, this.identitySymbol, pathNode, logic, adapter, createChildNode);
1078
+ this.childrenMap = this.createChildrenMap();
1035
1079
  this.fieldManager.structures.add(this);
1036
1080
  }
1037
1081
  }
1038
1082
  let globalId = 0;
1039
- const ROOT_PATH_KEYS = computed(() => [], {
1040
- ...(ngDevMode ? {
1041
- debugName: "ROOT_PATH_KEYS"
1042
- } : {})
1043
- });
1083
+ const ROOT_PATH_KEYS = computed(() => [], ...(ngDevMode ? [{
1084
+ debugName: "ROOT_PATH_KEYS"
1085
+ }] : []));
1044
1086
  const ROOT_KEY_IN_PARENT = computed(() => {
1045
1087
  throw new Error(`RuntimeError: the top-level field in the form has no parent`);
1046
- }, {
1047
- ...(ngDevMode ? {
1048
- debugName: "ROOT_KEY_IN_PARENT"
1049
- } : {})
1050
- });
1051
- function makeChildrenMapSignal(node, valueSignal, identitySymbol, pathNode, logic, adapter, createChildNode) {
1052
- return linkedSignal({
1053
- source: valueSignal,
1054
- computation: (value, previous) => {
1055
- let childrenMap = previous?.value;
1056
- if (!isObject(value)) {
1057
- return undefined;
1058
- }
1059
- const isValueArray = isArray(value);
1060
- if (childrenMap !== undefined) {
1061
- let oldKeys = undefined;
1062
- if (isValueArray) {
1063
- oldKeys = new Set(childrenMap.keys());
1064
- for (let i = 0; i < value.length; i++) {
1065
- const childValue = value[i];
1066
- if (isObject(childValue) && childValue.hasOwnProperty(identitySymbol)) {
1067
- oldKeys.delete(childValue[identitySymbol]);
1068
- } else {
1069
- oldKeys.delete(i.toString());
1070
- }
1071
- }
1072
- for (const key of oldKeys) {
1073
- childrenMap.delete(key);
1074
- }
1075
- } else {
1076
- for (let key of childrenMap.keys()) {
1077
- if (!value.hasOwnProperty(key)) {
1078
- childrenMap.delete(key);
1079
- }
1080
- }
1081
- }
1082
- }
1083
- for (let key of Object.keys(value)) {
1084
- let trackingId = undefined;
1085
- const childValue = value[key];
1086
- if (childValue === undefined) {
1087
- childrenMap?.delete(key);
1088
- continue;
1089
- }
1090
- if (isValueArray && isObject(childValue) && !isArray(childValue)) {
1091
- trackingId = childValue[identitySymbol] ??= Symbol(ngDevMode ? `id:${globalId++}` : '');
1092
- }
1093
- const identity = trackingId ?? key;
1094
- if (childrenMap?.has(identity)) {
1095
- continue;
1096
- }
1097
- let childPath;
1098
- let childLogic;
1099
- if (isValueArray) {
1100
- childPath = pathNode.getChild(DYNAMIC);
1101
- childLogic = logic.getChild(DYNAMIC);
1102
- } else {
1103
- childPath = pathNode.getChild(key);
1104
- childLogic = logic.getChild(key);
1105
- }
1106
- childrenMap ??= new Map();
1107
- childrenMap.set(identity, createChildNode({
1108
- kind: 'child',
1109
- parent: node,
1110
- pathNode: childPath,
1111
- logic: childLogic,
1112
- initialKeyInParent: key,
1113
- identityInParent: trackingId,
1114
- fieldAdapter: adapter
1115
- }));
1116
- }
1117
- return childrenMap;
1118
- },
1119
- equal: () => false
1120
- });
1121
- }
1088
+ }, ...(ngDevMode ? [{
1089
+ debugName: "ROOT_KEY_IN_PARENT"
1090
+ }] : []));
1122
1091
  function getDebugName(node) {
1123
1092
  return `<root>.${node.structure.pathKeys().join('.')}`;
1124
1093
  }
1094
+ function maybeRemoveStaleArrayFields(prevData, value, identitySymbol) {
1095
+ let data;
1096
+ const oldKeys = new Set(prevData.byPropertyKey.keys());
1097
+ const oldTracking = new Set(prevData.byTrackingKey?.keys());
1098
+ for (let i = 0; i < value.length; i++) {
1099
+ const childValue = value[i];
1100
+ oldKeys.delete(i.toString());
1101
+ if (isObject(childValue) && childValue.hasOwnProperty(identitySymbol)) {
1102
+ oldTracking.delete(childValue[identitySymbol]);
1103
+ }
1104
+ }
1105
+ if (oldKeys.size > 0) {
1106
+ data ??= {
1107
+ ...prevData
1108
+ };
1109
+ for (const key of oldKeys) {
1110
+ data.byPropertyKey.delete(key);
1111
+ }
1112
+ }
1113
+ if (oldTracking.size > 0) {
1114
+ data ??= {
1115
+ ...prevData
1116
+ };
1117
+ for (const id of oldTracking) {
1118
+ data.byTrackingKey?.delete(id);
1119
+ }
1120
+ }
1121
+ return data;
1122
+ }
1123
+ function maybeRemoveStaleObjectFields(prevData, value) {
1124
+ let data;
1125
+ for (const key of prevData.byPropertyKey.keys()) {
1126
+ if (!value.hasOwnProperty(key)) {
1127
+ data ??= {
1128
+ ...prevData
1129
+ };
1130
+ data.byPropertyKey.delete(key);
1131
+ }
1132
+ }
1133
+ return data;
1134
+ }
1125
1135
 
1126
1136
  class FieldSubmitState {
1127
1137
  node;
1128
- selfSubmitting = signal(false, {
1129
- ...(ngDevMode ? {
1130
- debugName: "selfSubmitting"
1131
- } : {})
1132
- });
1138
+ selfSubmitting = signal(false, ...(ngDevMode ? [{
1139
+ debugName: "selfSubmitting"
1140
+ }] : []));
1133
1141
  serverErrors;
1134
1142
  constructor(node) {
1135
1143
  this.node = node;
@@ -1143,11 +1151,9 @@ class FieldSubmitState {
1143
1151
  }
1144
1152
  submitting = computed(() => {
1145
1153
  return this.selfSubmitting() || (this.node.structure.parent?.submitting() ?? false);
1146
- }, {
1147
- ...(ngDevMode ? {
1148
- debugName: "submitting"
1149
- } : {})
1150
- });
1154
+ }, ...(ngDevMode ? [{
1155
+ debugName: "submitting"
1156
+ }] : []));
1151
1157
  }
1152
1158
 
1153
1159
  class FieldNode {
@@ -1162,7 +1168,9 @@ class FieldNode {
1162
1168
  return this._context ??= new FieldNodeContext(this);
1163
1169
  }
1164
1170
  fieldProxy = new Proxy(() => this, FIELD_PROXY_HANDLER);
1171
+ pathNode;
1165
1172
  constructor(options) {
1173
+ this.pathNode = options.pathNode;
1166
1174
  this.fieldAdapter = options.fieldAdapter;
1167
1175
  this.structure = this.fieldAdapter.createStructure(this, options);
1168
1176
  this.validationState = this.fieldAdapter.createValidationState(this, options);
@@ -1186,11 +1194,9 @@ class FieldNode {
1186
1194
  get value() {
1187
1195
  return this.structure.value;
1188
1196
  }
1189
- _controlValue = linkedSignal(() => this.value(), {
1190
- ...(ngDevMode ? {
1191
- debugName: "_controlValue"
1192
- } : {})
1193
- });
1197
+ _controlValue = linkedSignal(() => this.value(), ...(ngDevMode ? [{
1198
+ debugName: "_controlValue"
1199
+ }] : []));
1194
1200
  get controlValue() {
1195
1201
  return this._controlValue.asReadonly();
1196
1202
  }
@@ -1239,26 +1245,23 @@ class FieldNode {
1239
1245
  get name() {
1240
1246
  return this.nodeState.name;
1241
1247
  }
1242
- metadataOrUndefined(key) {
1243
- return this.hasMetadata(key) ? this.metadata(key) : undefined;
1244
- }
1245
1248
  get max() {
1246
- return this.metadataOrUndefined(MAX);
1249
+ return this.metadata(MAX);
1247
1250
  }
1248
1251
  get maxLength() {
1249
- return this.metadataOrUndefined(MAX_LENGTH);
1252
+ return this.metadata(MAX_LENGTH);
1250
1253
  }
1251
1254
  get min() {
1252
- return this.metadataOrUndefined(MIN);
1255
+ return this.metadata(MIN);
1253
1256
  }
1254
1257
  get minLength() {
1255
- return this.metadataOrUndefined(MIN_LENGTH);
1258
+ return this.metadata(MIN_LENGTH);
1256
1259
  }
1257
1260
  get pattern() {
1258
- return this.metadataOrUndefined(PATTERN) ?? EMPTY;
1261
+ return this.metadata(PATTERN) ?? EMPTY;
1259
1262
  }
1260
1263
  get required() {
1261
- return this.metadataOrUndefined(REQUIRED) ?? FALSE;
1264
+ return this.metadata(REQUIRED) ?? FALSE;
1262
1265
  }
1263
1266
  metadata(key) {
1264
1267
  return this.metadataState.get(key);
@@ -1278,7 +1281,7 @@ class FieldNode {
1278
1281
  untracked(() => this._reset(value));
1279
1282
  }
1280
1283
  _reset(value) {
1281
- if (value) {
1284
+ if (value !== undefined) {
1282
1285
  this.value.set(value);
1283
1286
  }
1284
1287
  this.nodeState.markAsUntouched();
@@ -1314,36 +1317,45 @@ class FieldNode {
1314
1317
  static newRoot(fieldManager, value, pathNode, adapter) {
1315
1318
  return adapter.newRoot(fieldManager, value, pathNode, adapter);
1316
1319
  }
1317
- static newChild(options) {
1318
- return options.fieldAdapter.newChild(options);
1319
- }
1320
1320
  createStructure(options) {
1321
- return options.kind === 'root' ? new RootFieldNodeStructure(this, options.pathNode, options.logic, options.fieldManager, options.value, options.fieldAdapter, FieldNode.newChild) : new ChildFieldNodeStructure(this, options.pathNode, options.logic, options.parent, options.identityInParent, options.initialKeyInParent, options.fieldAdapter, FieldNode.newChild);
1321
+ return options.kind === 'root' ? new RootFieldNodeStructure(this, options.logic, options.fieldManager, options.value, this.newChild.bind(this)) : new ChildFieldNodeStructure(this, options.logic, options.parent, options.identityInParent, options.initialKeyInParent, this.newChild.bind(this));
1322
+ }
1323
+ newChild(key, trackingId, isArray) {
1324
+ let childPath;
1325
+ let childLogic;
1326
+ if (isArray) {
1327
+ childPath = this.pathNode.getChild(DYNAMIC);
1328
+ childLogic = this.structure.logic.getChild(DYNAMIC);
1329
+ } else {
1330
+ childPath = this.pathNode.getChild(key);
1331
+ childLogic = this.structure.logic.getChild(key);
1332
+ }
1333
+ return this.fieldAdapter.newChild({
1334
+ kind: 'child',
1335
+ parent: this,
1336
+ pathNode: childPath,
1337
+ logic: childLogic,
1338
+ initialKeyInParent: key,
1339
+ identityInParent: trackingId,
1340
+ fieldAdapter: this.fieldAdapter
1341
+ });
1322
1342
  }
1323
1343
  }
1324
- const EMPTY = computed(() => [], {
1325
- ...(ngDevMode ? {
1326
- debugName: "EMPTY"
1327
- } : {})
1328
- });
1329
- const FALSE = computed(() => false, {
1330
- ...(ngDevMode ? {
1331
- debugName: "FALSE"
1332
- } : {})
1333
- });
1344
+ const EMPTY = computed(() => [], ...(ngDevMode ? [{
1345
+ debugName: "EMPTY"
1346
+ }] : []));
1347
+ const FALSE = computed(() => false, ...(ngDevMode ? [{
1348
+ debugName: "FALSE"
1349
+ }] : []));
1334
1350
 
1335
1351
  class FieldNodeState {
1336
1352
  node;
1337
- selfTouched = signal(false, {
1338
- ...(ngDevMode ? {
1339
- debugName: "selfTouched"
1340
- } : {})
1341
- });
1342
- selfDirty = signal(false, {
1343
- ...(ngDevMode ? {
1344
- debugName: "selfDirty"
1345
- } : {})
1346
- });
1353
+ selfTouched = signal(false, ...(ngDevMode ? [{
1354
+ debugName: "selfTouched"
1355
+ }] : []));
1356
+ selfDirty = signal(false, ...(ngDevMode ? [{
1357
+ debugName: "selfDirty"
1358
+ }] : []));
1347
1359
  markAsTouched() {
1348
1360
  this.selfTouched.set(true);
1349
1361
  }
@@ -1356,80 +1368,60 @@ class FieldNodeState {
1356
1368
  markAsUntouched() {
1357
1369
  this.selfTouched.set(false);
1358
1370
  }
1359
- fieldBindings = signal([], {
1360
- ...(ngDevMode ? {
1361
- debugName: "fieldBindings"
1362
- } : {})
1363
- });
1371
+ fieldBindings = signal([], ...(ngDevMode ? [{
1372
+ debugName: "fieldBindings"
1373
+ }] : []));
1364
1374
  constructor(node) {
1365
1375
  this.node = node;
1366
1376
  }
1367
1377
  dirty = computed(() => {
1368
1378
  const selfDirtyValue = this.selfDirty() && !this.isNonInteractive();
1369
- return reduceChildren(this.node, selfDirtyValue, (child, value) => value || child.nodeState.dirty(), shortCircuitTrue);
1370
- }, {
1371
- ...(ngDevMode ? {
1372
- debugName: "dirty"
1373
- } : {})
1374
- });
1379
+ return this.node.structure.reduceChildren(selfDirtyValue, (child, value) => value || child.nodeState.dirty(), shortCircuitTrue);
1380
+ }, ...(ngDevMode ? [{
1381
+ debugName: "dirty"
1382
+ }] : []));
1375
1383
  touched = computed(() => {
1376
1384
  const selfTouchedValue = this.selfTouched() && !this.isNonInteractive();
1377
- return reduceChildren(this.node, selfTouchedValue, (child, value) => value || child.nodeState.touched(), shortCircuitTrue);
1378
- }, {
1379
- ...(ngDevMode ? {
1380
- debugName: "touched"
1381
- } : {})
1382
- });
1383
- disabledReasons = computed(() => [...(this.node.structure.parent?.nodeState.disabledReasons() ?? []), ...this.node.logicNode.logic.disabledReasons.compute(this.node.context)], {
1384
- ...(ngDevMode ? {
1385
- debugName: "disabledReasons"
1386
- } : {})
1387
- });
1388
- disabled = computed(() => !!this.disabledReasons().length, {
1389
- ...(ngDevMode ? {
1390
- debugName: "disabled"
1391
- } : {})
1392
- });
1393
- readonly = computed(() => (this.node.structure.parent?.nodeState.readonly() || this.node.logicNode.logic.readonly.compute(this.node.context)) ?? false, {
1394
- ...(ngDevMode ? {
1395
- debugName: "readonly"
1396
- } : {})
1397
- });
1398
- hidden = computed(() => (this.node.structure.parent?.nodeState.hidden() || this.node.logicNode.logic.hidden.compute(this.node.context)) ?? false, {
1399
- ...(ngDevMode ? {
1400
- debugName: "hidden"
1401
- } : {})
1402
- });
1385
+ return this.node.structure.reduceChildren(selfTouchedValue, (child, value) => value || child.nodeState.touched(), shortCircuitTrue);
1386
+ }, ...(ngDevMode ? [{
1387
+ debugName: "touched"
1388
+ }] : []));
1389
+ disabledReasons = computed(() => [...(this.node.structure.parent?.nodeState.disabledReasons() ?? []), ...this.node.logicNode.logic.disabledReasons.compute(this.node.context)], ...(ngDevMode ? [{
1390
+ debugName: "disabledReasons"
1391
+ }] : []));
1392
+ disabled = computed(() => !!this.disabledReasons().length, ...(ngDevMode ? [{
1393
+ debugName: "disabled"
1394
+ }] : []));
1395
+ readonly = computed(() => (this.node.structure.parent?.nodeState.readonly() || this.node.logicNode.logic.readonly.compute(this.node.context)) ?? false, ...(ngDevMode ? [{
1396
+ debugName: "readonly"
1397
+ }] : []));
1398
+ hidden = computed(() => (this.node.structure.parent?.nodeState.hidden() || this.node.logicNode.logic.hidden.compute(this.node.context)) ?? false, ...(ngDevMode ? [{
1399
+ debugName: "hidden"
1400
+ }] : []));
1403
1401
  name = computed(() => {
1404
1402
  const parent = this.node.structure.parent;
1405
1403
  if (!parent) {
1406
1404
  return this.node.structure.fieldManager.rootName;
1407
1405
  }
1408
1406
  return `${parent.name()}.${this.node.structure.keyInParent()}`;
1409
- }, {
1410
- ...(ngDevMode ? {
1411
- debugName: "name"
1412
- } : {})
1413
- });
1407
+ }, ...(ngDevMode ? [{
1408
+ debugName: "name"
1409
+ }] : []));
1414
1410
  debouncer = computed(() => {
1415
- if (this.node.logicNode.logic.hasAggregateMetadata(DEBOUNCER)) {
1416
- const debouncerLogic = this.node.logicNode.logic.getAggregateMetadata(DEBOUNCER);
1411
+ if (this.node.logicNode.logic.hasMetadata(DEBOUNCER)) {
1412
+ const debouncerLogic = this.node.logicNode.logic.getMetadata(DEBOUNCER);
1417
1413
  const debouncer = debouncerLogic.compute(this.node.context);
1418
1414
  if (debouncer) {
1419
1415
  return signal => debouncer(this.node.context, signal);
1420
1416
  }
1421
1417
  }
1422
1418
  return this.node.structure.parent?.nodeState.debouncer?.();
1423
- }, {
1424
- ...(ngDevMode ? {
1425
- debugName: "debouncer"
1426
- } : {})
1427
- });
1428
- isNonInteractive = computed(() => this.hidden() || this.disabled() || this.readonly(), {
1429
- ...(ngDevMode ? {
1430
- debugName: "isNonInteractive"
1431
- } : {})
1432
- });
1419
+ }, ...(ngDevMode ? [{
1420
+ debugName: "debouncer"
1421
+ }] : []));
1422
+ isNonInteractive = computed(() => this.hidden() || this.disabled() || this.readonly(), ...(ngDevMode ? [{
1423
+ debugName: "isNonInteractive"
1424
+ }] : []));
1433
1425
  }
1434
1426
 
1435
1427
  class BasicFieldAdapter {
@@ -1582,5 +1574,5 @@ function markAllAsTouched(node) {
1582
1574
  }
1583
1575
  }
1584
1576
 
1585
- export { AggregateMetadataKey, BasicFieldAdapter, DEBOUNCER, FieldNode, FieldNodeState, FieldNodeStructure, FieldPathNode, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MetadataKey, PATTERN, REQUIRED, addDefaultField, andMetadataKey, apply, applyEach, applyWhen, applyWhenValue, assertPathIsCurrent, calculateValidationSelfStatus, createMetadataKey, form, getInjectorFromOptions, isArray, listMetadataKey, maxMetadataKey, minMetadataKey, normalizeFormArgs, orMetadataKey, reducedMetadataKey, schema, submit };
1577
+ export { BasicFieldAdapter, DEBOUNCER, FieldNode, FieldNodeState, FieldNodeStructure, FieldPathNode, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MetadataKey, MetadataReducer, PATTERN, REQUIRED, addDefaultField, apply, applyEach, applyWhen, applyWhenValue, assertPathIsCurrent, calculateValidationSelfStatus, createManagedMetadataKey, createMetadataKey, form, getInjectorFromOptions, isArray, metadata, normalizeFormArgs, schema, submit };
1586
1578
  //# sourceMappingURL=_structure-chunk.mjs.map