@angular/forms 21.0.4 → 21.1.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/_structure-chunk.mjs +385 -453
- package/fesm2022/_structure-chunk.mjs.map +1 -1
- package/fesm2022/forms.mjs +133 -133
- package/fesm2022/forms.mjs.map +1 -1
- package/fesm2022/signals-compat.mjs +6 -9
- package/fesm2022/signals-compat.mjs.map +1 -1
- package/fesm2022/signals.mjs +293 -276
- package/fesm2022/signals.mjs.map +1 -1
- package/package.json +4 -4
- package/types/_structure-chunk.d.ts +708 -788
- package/types/forms.d.ts +1 -1
- package/types/signals-compat.d.ts +1 -1
- package/types/signals.d.ts +225 -191
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v21.0.
|
|
2
|
+
* @license Angular v21.1.0-next.1
|
|
3
3
|
* (c) 2010-2025 Google LLC. https://angular.dev/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { computed, untracked, runInInjectionContext, linkedSignal, Injector, 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
|
-
|
|
12
|
-
|
|
13
|
-
return boundPathDepth;
|
|
11
|
+
function isArray(value) {
|
|
12
|
+
return Array.isArray(value);
|
|
14
13
|
}
|
|
15
|
-
function
|
|
16
|
-
return (
|
|
17
|
-
try {
|
|
18
|
-
boundPathDepth = depth;
|
|
19
|
-
return fn(...args);
|
|
20
|
-
} finally {
|
|
21
|
-
boundPathDepth = 0;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
14
|
+
function isObject(value) {
|
|
15
|
+
return (typeof value === 'object' || typeof value === 'function') && value != null;
|
|
24
16
|
}
|
|
25
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;
|
|
27
|
+
}
|
|
28
|
+
value = fn(child, value);
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
26
32
|
function shortCircuitFalse(value) {
|
|
27
33
|
return !value;
|
|
28
34
|
}
|
|
@@ -36,11 +42,131 @@ function getInjectorFromOptions(options) {
|
|
|
36
42
|
return options.parent.structure.root.structure.injector;
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
function
|
|
40
|
-
|
|
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';
|
|
41
53
|
}
|
|
42
|
-
|
|
43
|
-
|
|
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
|
+
}, ...(ngDevMode ? [{
|
|
65
|
+
debugName: "rawSyncTreeErrors"
|
|
66
|
+
}] : []));
|
|
67
|
+
syncErrors = computed(() => {
|
|
68
|
+
if (this.shouldSkipValidation()) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return [...this.node.logicNode.logic.syncErrors.compute(this.node.context), ...this.syncTreeErrors(), ...normalizeErrors(this.node.submitState.serverErrors())];
|
|
72
|
+
}, ...(ngDevMode ? [{
|
|
73
|
+
debugName: "syncErrors"
|
|
74
|
+
}] : []));
|
|
75
|
+
syncValid = computed(() => {
|
|
76
|
+
if (this.shouldSkipValidation()) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return reduceChildren(this.node, this.syncErrors().length === 0, (child, value) => value && child.validationState.syncValid(), shortCircuitFalse);
|
|
80
|
+
}, ...(ngDevMode ? [{
|
|
81
|
+
debugName: "syncValid"
|
|
82
|
+
}] : []));
|
|
83
|
+
syncTreeErrors = computed(() => this.rawSyncTreeErrors().filter(err => err.field === this.node.fieldProxy), ...(ngDevMode ? [{
|
|
84
|
+
debugName: "syncTreeErrors"
|
|
85
|
+
}] : []));
|
|
86
|
+
rawAsyncErrors = computed(() => {
|
|
87
|
+
if (this.shouldSkipValidation()) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
return [...this.node.logicNode.logic.asyncErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawAsyncErrors() ?? [])];
|
|
91
|
+
}, ...(ngDevMode ? [{
|
|
92
|
+
debugName: "rawAsyncErrors"
|
|
93
|
+
}] : []));
|
|
94
|
+
asyncErrors = computed(() => {
|
|
95
|
+
if (this.shouldSkipValidation()) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
return this.rawAsyncErrors().filter(err => err === 'pending' || err.field === this.node.fieldProxy);
|
|
99
|
+
}, ...(ngDevMode ? [{
|
|
100
|
+
debugName: "asyncErrors"
|
|
101
|
+
}] : []));
|
|
102
|
+
errors = computed(() => [...this.syncErrors(), ...this.asyncErrors().filter(err => err !== 'pending')], ...(ngDevMode ? [{
|
|
103
|
+
debugName: "errors"
|
|
104
|
+
}] : []));
|
|
105
|
+
errorSummary = computed(() => reduceChildren(this.node, this.errors(), (child, result) => [...result, ...child.errorSummary()]), ...(ngDevMode ? [{
|
|
106
|
+
debugName: "errorSummary"
|
|
107
|
+
}] : []));
|
|
108
|
+
pending = computed(() => reduceChildren(this.node, this.asyncErrors().includes('pending'), (child, value) => value || child.validationState.asyncErrors().includes('pending')), ...(ngDevMode ? [{
|
|
109
|
+
debugName: "pending"
|
|
110
|
+
}] : []));
|
|
111
|
+
status = computed(() => {
|
|
112
|
+
if (this.shouldSkipValidation()) {
|
|
113
|
+
return 'valid';
|
|
114
|
+
}
|
|
115
|
+
let ownStatus = calculateValidationSelfStatus(this);
|
|
116
|
+
return reduceChildren(this.node, ownStatus, (child, value) => {
|
|
117
|
+
if (value === 'invalid' || child.validationState.status() === 'invalid') {
|
|
118
|
+
return 'invalid';
|
|
119
|
+
} else if (value === 'unknown' || child.validationState.status() === 'unknown') {
|
|
120
|
+
return 'unknown';
|
|
121
|
+
}
|
|
122
|
+
return 'valid';
|
|
123
|
+
}, v => v === 'invalid');
|
|
124
|
+
}, ...(ngDevMode ? [{
|
|
125
|
+
debugName: "status"
|
|
126
|
+
}] : []));
|
|
127
|
+
valid = computed(() => this.status() === 'valid', ...(ngDevMode ? [{
|
|
128
|
+
debugName: "valid"
|
|
129
|
+
}] : []));
|
|
130
|
+
invalid = computed(() => this.status() === 'invalid', ...(ngDevMode ? [{
|
|
131
|
+
debugName: "invalid"
|
|
132
|
+
}] : []));
|
|
133
|
+
shouldSkipValidation = computed(() => this.node.hidden() || this.node.disabled() || this.node.readonly(), ...(ngDevMode ? [{
|
|
134
|
+
debugName: "shouldSkipValidation"
|
|
135
|
+
}] : []));
|
|
136
|
+
}
|
|
137
|
+
function normalizeErrors(error) {
|
|
138
|
+
if (error === undefined) {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
if (isArray(error)) {
|
|
142
|
+
return error;
|
|
143
|
+
}
|
|
144
|
+
return [error];
|
|
145
|
+
}
|
|
146
|
+
function addDefaultField(errors, field) {
|
|
147
|
+
if (isArray(errors)) {
|
|
148
|
+
for (const error of errors) {
|
|
149
|
+
error.field ??= field;
|
|
150
|
+
}
|
|
151
|
+
} else if (errors) {
|
|
152
|
+
errors.field ??= field;
|
|
153
|
+
}
|
|
154
|
+
return errors;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let boundPathDepth = 0;
|
|
158
|
+
function getBoundPathDepth() {
|
|
159
|
+
return boundPathDepth;
|
|
160
|
+
}
|
|
161
|
+
function setBoundPathDepthForResolution(fn, depth) {
|
|
162
|
+
return (...args) => {
|
|
163
|
+
try {
|
|
164
|
+
boundPathDepth = depth;
|
|
165
|
+
return fn(...args);
|
|
166
|
+
} finally {
|
|
167
|
+
boundPathDepth = 0;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
44
170
|
}
|
|
45
171
|
|
|
46
172
|
const DYNAMIC = Symbol();
|
|
@@ -103,10 +229,10 @@ class ArrayMergeLogic extends ArrayMergeIgnoreLogic {
|
|
|
103
229
|
super(predicates, undefined);
|
|
104
230
|
}
|
|
105
231
|
}
|
|
106
|
-
class
|
|
232
|
+
class AggregateMetadataMergeLogic extends AbstractLogic {
|
|
107
233
|
key;
|
|
108
234
|
get defaultValue() {
|
|
109
|
-
return this.key.
|
|
235
|
+
return this.key.getInitial();
|
|
110
236
|
}
|
|
111
237
|
constructor(predicates, key) {
|
|
112
238
|
super(predicates);
|
|
@@ -114,13 +240,13 @@ class MetadataMergeLogic extends AbstractLogic {
|
|
|
114
240
|
}
|
|
115
241
|
compute(ctx) {
|
|
116
242
|
if (this.fns.length === 0) {
|
|
117
|
-
return this.key.
|
|
243
|
+
return this.key.getInitial();
|
|
118
244
|
}
|
|
119
|
-
let acc = this.key.
|
|
245
|
+
let acc = this.key.getInitial();
|
|
120
246
|
for (let i = 0; i < this.fns.length; i++) {
|
|
121
247
|
const item = this.fns[i](ctx);
|
|
122
248
|
if (item !== IGNORED) {
|
|
123
|
-
acc = this.key.
|
|
249
|
+
acc = this.key.reduce(acc, item);
|
|
124
250
|
}
|
|
125
251
|
}
|
|
126
252
|
return acc;
|
|
@@ -152,7 +278,8 @@ class LogicContainer {
|
|
|
152
278
|
syncErrors;
|
|
153
279
|
syncTreeErrors;
|
|
154
280
|
asyncErrors;
|
|
155
|
-
|
|
281
|
+
aggregateMetadataKeys = new Map();
|
|
282
|
+
metadataFactories = new Map();
|
|
156
283
|
constructor(predicates) {
|
|
157
284
|
this.predicates = predicates;
|
|
158
285
|
this.hidden = new BooleanOrLogic(predicates);
|
|
@@ -162,17 +289,26 @@ class LogicContainer {
|
|
|
162
289
|
this.syncTreeErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
|
|
163
290
|
this.asyncErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
|
|
164
291
|
}
|
|
165
|
-
|
|
166
|
-
return this.
|
|
292
|
+
hasAggregateMetadata(key) {
|
|
293
|
+
return this.aggregateMetadataKeys.has(key);
|
|
167
294
|
}
|
|
168
|
-
|
|
169
|
-
return this.
|
|
295
|
+
getAggregateMetadataEntries() {
|
|
296
|
+
return this.aggregateMetadataKeys.entries();
|
|
170
297
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
298
|
+
getMetadataFactoryEntries() {
|
|
299
|
+
return this.metadataFactories.entries();
|
|
300
|
+
}
|
|
301
|
+
getAggregateMetadata(key) {
|
|
302
|
+
if (!this.aggregateMetadataKeys.has(key)) {
|
|
303
|
+
this.aggregateMetadataKeys.set(key, new AggregateMetadataMergeLogic(this.predicates, key));
|
|
174
304
|
}
|
|
175
|
-
return this.
|
|
305
|
+
return this.aggregateMetadataKeys.get(key);
|
|
306
|
+
}
|
|
307
|
+
addMetadataFactory(key, factory) {
|
|
308
|
+
if (this.metadataFactories.has(key)) {
|
|
309
|
+
throw new Error(`Can't define value twice for the same MetadataKey`);
|
|
310
|
+
}
|
|
311
|
+
this.metadataFactories.set(key, factory);
|
|
176
312
|
}
|
|
177
313
|
mergeIn(other) {
|
|
178
314
|
this.hidden.mergeIn(other.hidden);
|
|
@@ -181,9 +317,11 @@ class LogicContainer {
|
|
|
181
317
|
this.syncErrors.mergeIn(other.syncErrors);
|
|
182
318
|
this.syncTreeErrors.mergeIn(other.syncTreeErrors);
|
|
183
319
|
this.asyncErrors.mergeIn(other.asyncErrors);
|
|
184
|
-
for (const key of other.
|
|
185
|
-
|
|
186
|
-
|
|
320
|
+
for (const [key, metadataLogic] of other.getAggregateMetadataEntries()) {
|
|
321
|
+
this.getAggregateMetadata(key).mergeIn(metadataLogic);
|
|
322
|
+
}
|
|
323
|
+
for (const [key, metadataFactory] of other.getMetadataFactoryEntries()) {
|
|
324
|
+
this.addMetadataFactory(key, metadataFactory);
|
|
187
325
|
}
|
|
188
326
|
}
|
|
189
327
|
}
|
|
@@ -221,8 +359,11 @@ class LogicNodeBuilder extends AbstractLogicNodeBuilder {
|
|
|
221
359
|
addAsyncErrorRule(logic) {
|
|
222
360
|
this.getCurrent().addAsyncErrorRule(logic);
|
|
223
361
|
}
|
|
224
|
-
|
|
225
|
-
this.getCurrent().
|
|
362
|
+
addAggregateMetadataRule(key, logic) {
|
|
363
|
+
this.getCurrent().addAggregateMetadataRule(key, logic);
|
|
364
|
+
}
|
|
365
|
+
addMetadataFactory(key, factory) {
|
|
366
|
+
this.getCurrent().addMetadataFactory(key, factory);
|
|
226
367
|
}
|
|
227
368
|
getChild(key) {
|
|
228
369
|
if (key === DYNAMIC) {
|
|
@@ -294,8 +435,11 @@ class NonMergeableLogicNodeBuilder extends AbstractLogicNodeBuilder {
|
|
|
294
435
|
addAsyncErrorRule(logic) {
|
|
295
436
|
this.logic.asyncErrors.push(setBoundPathDepthForResolution(logic, this.depth));
|
|
296
437
|
}
|
|
297
|
-
|
|
298
|
-
this.logic.
|
|
438
|
+
addAggregateMetadataRule(key, logic) {
|
|
439
|
+
this.logic.getAggregateMetadata(key).push(setBoundPathDepthForResolution(logic, this.depth));
|
|
440
|
+
}
|
|
441
|
+
addMetadataFactory(key, factory) {
|
|
442
|
+
this.logic.addMetadataFactory(key, setBoundPathDepthForResolution(factory, this.depth));
|
|
299
443
|
}
|
|
300
444
|
getChild(key) {
|
|
301
445
|
if (!this.children.has(key)) {
|
|
@@ -513,196 +657,64 @@ function assertPathIsCurrent(path) {
|
|
|
513
657
|
}
|
|
514
658
|
}
|
|
515
659
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
pathNode.builder.addMetadataRule(key, logic);
|
|
520
|
-
return key;
|
|
660
|
+
class MetadataKey {
|
|
661
|
+
brand;
|
|
662
|
+
constructor() {}
|
|
521
663
|
}
|
|
522
|
-
|
|
523
|
-
|
|
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
|
-
};
|
|
664
|
+
function createMetadataKey() {
|
|
665
|
+
return new MetadataKey();
|
|
570
666
|
}
|
|
571
|
-
class
|
|
572
|
-
|
|
573
|
-
|
|
667
|
+
class AggregateMetadataKey {
|
|
668
|
+
reduce;
|
|
669
|
+
getInitial;
|
|
574
670
|
brand;
|
|
575
|
-
constructor(
|
|
576
|
-
this.
|
|
577
|
-
this.
|
|
671
|
+
constructor(reduce, getInitial) {
|
|
672
|
+
this.reduce = reduce;
|
|
673
|
+
this.getInitial = getInitial;
|
|
578
674
|
}
|
|
579
675
|
}
|
|
580
|
-
function
|
|
581
|
-
return new
|
|
676
|
+
function reducedMetadataKey(reduce, getInitial) {
|
|
677
|
+
return new AggregateMetadataKey(reduce, getInitial);
|
|
582
678
|
}
|
|
583
|
-
function
|
|
584
|
-
return
|
|
585
|
-
}
|
|
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';
|
|
679
|
+
function listMetadataKey() {
|
|
680
|
+
return reducedMetadataKey((acc, item) => item === undefined ? acc : [...acc, item], () => []);
|
|
601
681
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
rawSyncTreeErrors = computed(() => {
|
|
608
|
-
if (this.shouldSkipValidation()) {
|
|
609
|
-
return [];
|
|
682
|
+
function minMetadataKey() {
|
|
683
|
+
return reducedMetadataKey((prev, next) => {
|
|
684
|
+
if (prev === undefined) {
|
|
685
|
+
return next;
|
|
610
686
|
}
|
|
611
|
-
|
|
612
|
-
|
|
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;
|
|
626
|
-
}
|
|
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 [];
|
|
687
|
+
if (next === undefined) {
|
|
688
|
+
return prev;
|
|
637
689
|
}
|
|
638
|
-
return
|
|
639
|
-
},
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
if (
|
|
644
|
-
return
|
|
690
|
+
return Math.min(prev, next);
|
|
691
|
+
}, () => undefined);
|
|
692
|
+
}
|
|
693
|
+
function maxMetadataKey() {
|
|
694
|
+
return reducedMetadataKey((prev, next) => {
|
|
695
|
+
if (prev === undefined) {
|
|
696
|
+
return next;
|
|
645
697
|
}
|
|
646
|
-
|
|
647
|
-
|
|
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';
|
|
698
|
+
if (next === undefined) {
|
|
699
|
+
return prev;
|
|
662
700
|
}
|
|
663
|
-
|
|
664
|
-
|
|
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
|
-
}] : []));
|
|
701
|
+
return Math.max(prev, next);
|
|
702
|
+
}, () => undefined);
|
|
684
703
|
}
|
|
685
|
-
function
|
|
686
|
-
|
|
687
|
-
return [];
|
|
688
|
-
}
|
|
689
|
-
if (isArray(error)) {
|
|
690
|
-
return error;
|
|
691
|
-
}
|
|
692
|
-
return [error];
|
|
704
|
+
function orMetadataKey() {
|
|
705
|
+
return reducedMetadataKey((prev, next) => prev || next, () => false);
|
|
693
706
|
}
|
|
694
|
-
function
|
|
695
|
-
|
|
696
|
-
for (const error of errors) {
|
|
697
|
-
error.field ??= field;
|
|
698
|
-
}
|
|
699
|
-
} else if (errors) {
|
|
700
|
-
errors.field ??= field;
|
|
701
|
-
}
|
|
702
|
-
return errors;
|
|
707
|
+
function andMetadataKey() {
|
|
708
|
+
return reducedMetadataKey((prev, next) => prev && next, () => true);
|
|
703
709
|
}
|
|
710
|
+
const REQUIRED = orMetadataKey();
|
|
711
|
+
const MIN = maxMetadataKey();
|
|
712
|
+
const MAX = minMetadataKey();
|
|
713
|
+
const MIN_LENGTH = maxMetadataKey();
|
|
714
|
+
const MAX_LENGTH = minMetadataKey();
|
|
715
|
+
const PATTERN = listMetadataKey();
|
|
704
716
|
|
|
705
|
-
const DEBOUNCER =
|
|
717
|
+
const DEBOUNCER = reducedMetadataKey((_, item) => item, () => undefined);
|
|
706
718
|
|
|
707
719
|
class FieldNodeContext {
|
|
708
720
|
node;
|
|
@@ -777,28 +789,31 @@ class FieldMetadataState {
|
|
|
777
789
|
metadata = new Map();
|
|
778
790
|
constructor(node) {
|
|
779
791
|
this.node = node;
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
const result = untracked(() => runInInjectionContext(this.node.structure.injector, () => key.create(computed(() => logic.compute(this.node.context)))));
|
|
784
|
-
this.metadata.set(key, result);
|
|
792
|
+
untracked(() => runInInjectionContext(this.node.structure.injector, () => {
|
|
793
|
+
for (const [key, factory] of this.node.logicNode.logic.getMetadataFactoryEntries()) {
|
|
794
|
+
this.metadata.set(key, factory(this.node.context));
|
|
785
795
|
}
|
|
786
|
-
}
|
|
796
|
+
}));
|
|
787
797
|
}
|
|
788
798
|
get(key) {
|
|
789
|
-
if (
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
799
|
+
if (key instanceof MetadataKey) {
|
|
800
|
+
return this.metadata.get(key);
|
|
801
|
+
}
|
|
802
|
+
if (!this.metadata.has(key)) {
|
|
803
|
+
const logic = this.node.logicNode.logic.getAggregateMetadata(key);
|
|
804
|
+
const result = computed(() => logic.compute(this.node.context), ...(ngDevMode ? [{
|
|
805
|
+
debugName: "result"
|
|
806
|
+
}] : []));
|
|
807
|
+
this.metadata.set(key, result);
|
|
797
808
|
}
|
|
798
809
|
return this.metadata.get(key);
|
|
799
810
|
}
|
|
800
811
|
has(key) {
|
|
801
|
-
|
|
812
|
+
if (key instanceof AggregateMetadataKey) {
|
|
813
|
+
return this.node.logicNode.logic.hasAggregateMetadata(key);
|
|
814
|
+
} else {
|
|
815
|
+
return this.metadata.has(key);
|
|
816
|
+
}
|
|
802
817
|
}
|
|
803
818
|
}
|
|
804
819
|
|
|
@@ -815,10 +830,7 @@ const FIELD_PROXY_HANDLER = {
|
|
|
815
830
|
return tgt.value().length;
|
|
816
831
|
}
|
|
817
832
|
if (p === Symbol.iterator) {
|
|
818
|
-
return
|
|
819
|
-
tgt.value();
|
|
820
|
-
return Array.prototype[Symbol.iterator].apply(tgt.fieldProxy);
|
|
821
|
-
};
|
|
833
|
+
return Array.prototype[p];
|
|
822
834
|
}
|
|
823
835
|
}
|
|
824
836
|
if (isObject(value)) {
|
|
@@ -873,8 +885,6 @@ function valueForWrite(sourceValue, newPropValue, prop) {
|
|
|
873
885
|
|
|
874
886
|
class FieldNodeStructure {
|
|
875
887
|
logic;
|
|
876
|
-
node;
|
|
877
|
-
createChildNode;
|
|
878
888
|
identitySymbol = Symbol();
|
|
879
889
|
_injector = undefined;
|
|
880
890
|
get injector() {
|
|
@@ -884,146 +894,32 @@ class FieldNodeStructure {
|
|
|
884
894
|
});
|
|
885
895
|
return this._injector;
|
|
886
896
|
}
|
|
887
|
-
constructor(logic
|
|
897
|
+
constructor(logic) {
|
|
888
898
|
this.logic = logic;
|
|
889
|
-
this.node = node;
|
|
890
|
-
this.createChildNode = createChildNode;
|
|
891
899
|
}
|
|
892
900
|
children() {
|
|
893
|
-
|
|
894
|
-
if (map === undefined) {
|
|
895
|
-
return [];
|
|
896
|
-
}
|
|
897
|
-
return Array.from(map.byPropertyKey.values()).map(child => untracked(child.reader));
|
|
901
|
+
return this.childrenMap()?.values() ?? [];
|
|
898
902
|
}
|
|
899
903
|
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) {
|
|
908
904
|
const map = this.childrenMap();
|
|
909
|
-
|
|
910
|
-
|
|
905
|
+
const value = this.value();
|
|
906
|
+
if (!map || !isObject(value)) {
|
|
907
|
+
return undefined;
|
|
911
908
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
if (
|
|
915
|
-
|
|
909
|
+
if (isArray(value)) {
|
|
910
|
+
const childValue = value[key];
|
|
911
|
+
if (isObject(childValue) && childValue.hasOwnProperty(this.identitySymbol)) {
|
|
912
|
+
key = childValue[this.identitySymbol];
|
|
916
913
|
}
|
|
917
|
-
value = fn(untracked(child.reader), value);
|
|
918
914
|
}
|
|
919
|
-
return
|
|
915
|
+
return map.get(typeof key === 'number' ? key.toString() : key);
|
|
920
916
|
}
|
|
921
917
|
destroy() {
|
|
922
918
|
this.injector.destroy();
|
|
923
919
|
}
|
|
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
|
-
}
|
|
1025
920
|
}
|
|
1026
921
|
class RootFieldNodeStructure extends FieldNodeStructure {
|
|
922
|
+
node;
|
|
1027
923
|
fieldManager;
|
|
1028
924
|
value;
|
|
1029
925
|
get parent() {
|
|
@@ -1039,15 +935,15 @@ class RootFieldNodeStructure extends FieldNodeStructure {
|
|
|
1039
935
|
return ROOT_KEY_IN_PARENT;
|
|
1040
936
|
}
|
|
1041
937
|
childrenMap;
|
|
1042
|
-
constructor(node, logic, fieldManager, value, createChildNode) {
|
|
1043
|
-
super(logic
|
|
938
|
+
constructor(node, pathNode, logic, fieldManager, value, adapter, createChildNode) {
|
|
939
|
+
super(logic);
|
|
940
|
+
this.node = node;
|
|
1044
941
|
this.fieldManager = fieldManager;
|
|
1045
942
|
this.value = value;
|
|
1046
|
-
this.childrenMap = this.
|
|
943
|
+
this.childrenMap = makeChildrenMapSignal(node, value, this.identitySymbol, pathNode, logic, adapter, createChildNode);
|
|
1047
944
|
}
|
|
1048
945
|
}
|
|
1049
946
|
class ChildFieldNodeStructure extends FieldNodeStructure {
|
|
1050
|
-
logic;
|
|
1051
947
|
parent;
|
|
1052
948
|
root;
|
|
1053
949
|
pathKeys;
|
|
@@ -1057,25 +953,47 @@ class ChildFieldNodeStructure extends FieldNodeStructure {
|
|
|
1057
953
|
get fieldManager() {
|
|
1058
954
|
return this.root.structure.fieldManager;
|
|
1059
955
|
}
|
|
1060
|
-
constructor(node, logic, parent, identityInParent, initialKeyInParent, createChildNode) {
|
|
1061
|
-
super(logic
|
|
1062
|
-
this.logic = logic;
|
|
956
|
+
constructor(node, pathNode, logic, parent, identityInParent, initialKeyInParent, adapter, createChildNode) {
|
|
957
|
+
super(logic);
|
|
1063
958
|
this.parent = parent;
|
|
1064
959
|
this.root = this.parent.structure.root;
|
|
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
960
|
this.pathKeys = computed(() => [...parent.structure.pathKeys(), this.keyInParent()], ...(ngDevMode ? [{
|
|
1075
961
|
debugName: "pathKeys"
|
|
1076
962
|
}] : []));
|
|
963
|
+
if (identityInParent === undefined) {
|
|
964
|
+
const key = initialKeyInParent;
|
|
965
|
+
this.keyInParent = computed(() => {
|
|
966
|
+
if (parent.structure.childrenMap()?.get(key) !== node) {
|
|
967
|
+
throw new Error(`RuntimeError: orphan field, looking for property '${key}' of ${getDebugName(parent)}`);
|
|
968
|
+
}
|
|
969
|
+
return key;
|
|
970
|
+
}, ...(ngDevMode ? [{
|
|
971
|
+
debugName: "keyInParent"
|
|
972
|
+
}] : []));
|
|
973
|
+
} else {
|
|
974
|
+
let lastKnownKey = initialKeyInParent;
|
|
975
|
+
this.keyInParent = computed(() => {
|
|
976
|
+
const parentValue = parent.structure.value();
|
|
977
|
+
if (!isArray(parentValue)) {
|
|
978
|
+
throw new Error(`RuntimeError: orphan field, expected ${getDebugName(parent)} to be an array`);
|
|
979
|
+
}
|
|
980
|
+
const data = parentValue[lastKnownKey];
|
|
981
|
+
if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
|
|
982
|
+
return lastKnownKey;
|
|
983
|
+
}
|
|
984
|
+
for (let i = 0; i < parentValue.length; i++) {
|
|
985
|
+
const data = parentValue[i];
|
|
986
|
+
if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
|
|
987
|
+
return lastKnownKey = i.toString();
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
throw new Error(`RuntimeError: orphan field, can't find element in array ${getDebugName(parent)}`);
|
|
991
|
+
}, ...(ngDevMode ? [{
|
|
992
|
+
debugName: "keyInParent"
|
|
993
|
+
}] : []));
|
|
994
|
+
}
|
|
1077
995
|
this.value = deepSignal(this.parent.structure.value, this.keyInParent);
|
|
1078
|
-
this.childrenMap = this.
|
|
996
|
+
this.childrenMap = makeChildrenMapSignal(node, this.value, this.identitySymbol, pathNode, logic, adapter, createChildNode);
|
|
1079
997
|
this.fieldManager.structures.add(this);
|
|
1080
998
|
}
|
|
1081
999
|
}
|
|
@@ -1088,50 +1006,80 @@ const ROOT_KEY_IN_PARENT = computed(() => {
|
|
|
1088
1006
|
}, ...(ngDevMode ? [{
|
|
1089
1007
|
debugName: "ROOT_KEY_IN_PARENT"
|
|
1090
1008
|
}] : []));
|
|
1009
|
+
function makeChildrenMapSignal(node, valueSignal, identitySymbol, pathNode, logic, adapter, createChildNode) {
|
|
1010
|
+
return linkedSignal({
|
|
1011
|
+
source: valueSignal,
|
|
1012
|
+
computation: (value, previous) => {
|
|
1013
|
+
let childrenMap = previous?.value;
|
|
1014
|
+
if (!isObject(value)) {
|
|
1015
|
+
return undefined;
|
|
1016
|
+
}
|
|
1017
|
+
const isValueArray = isArray(value);
|
|
1018
|
+
if (childrenMap !== undefined) {
|
|
1019
|
+
let oldKeys = undefined;
|
|
1020
|
+
if (isValueArray) {
|
|
1021
|
+
oldKeys = new Set(childrenMap.keys());
|
|
1022
|
+
for (let i = 0; i < value.length; i++) {
|
|
1023
|
+
const childValue = value[i];
|
|
1024
|
+
if (isObject(childValue) && childValue.hasOwnProperty(identitySymbol)) {
|
|
1025
|
+
oldKeys.delete(childValue[identitySymbol]);
|
|
1026
|
+
} else {
|
|
1027
|
+
oldKeys.delete(i.toString());
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
for (const key of oldKeys) {
|
|
1031
|
+
childrenMap.delete(key);
|
|
1032
|
+
}
|
|
1033
|
+
} else {
|
|
1034
|
+
for (let key of childrenMap.keys()) {
|
|
1035
|
+
if (!value.hasOwnProperty(key)) {
|
|
1036
|
+
childrenMap.delete(key);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
for (let key of Object.keys(value)) {
|
|
1042
|
+
let trackingId = undefined;
|
|
1043
|
+
const childValue = value[key];
|
|
1044
|
+
if (childValue === undefined) {
|
|
1045
|
+
childrenMap?.delete(key);
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
if (isValueArray && isObject(childValue) && !isArray(childValue)) {
|
|
1049
|
+
trackingId = childValue[identitySymbol] ??= Symbol(ngDevMode ? `id:${globalId++}` : '');
|
|
1050
|
+
}
|
|
1051
|
+
const identity = trackingId ?? key;
|
|
1052
|
+
if (childrenMap?.has(identity)) {
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
let childPath;
|
|
1056
|
+
let childLogic;
|
|
1057
|
+
if (isValueArray) {
|
|
1058
|
+
childPath = pathNode.getChild(DYNAMIC);
|
|
1059
|
+
childLogic = logic.getChild(DYNAMIC);
|
|
1060
|
+
} else {
|
|
1061
|
+
childPath = pathNode.getChild(key);
|
|
1062
|
+
childLogic = logic.getChild(key);
|
|
1063
|
+
}
|
|
1064
|
+
childrenMap ??= new Map();
|
|
1065
|
+
childrenMap.set(identity, createChildNode({
|
|
1066
|
+
kind: 'child',
|
|
1067
|
+
parent: node,
|
|
1068
|
+
pathNode: childPath,
|
|
1069
|
+
logic: childLogic,
|
|
1070
|
+
initialKeyInParent: key,
|
|
1071
|
+
identityInParent: trackingId,
|
|
1072
|
+
fieldAdapter: adapter
|
|
1073
|
+
}));
|
|
1074
|
+
}
|
|
1075
|
+
return childrenMap;
|
|
1076
|
+
},
|
|
1077
|
+
equal: () => false
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1091
1080
|
function getDebugName(node) {
|
|
1092
1081
|
return `<root>.${node.structure.pathKeys().join('.')}`;
|
|
1093
1082
|
}
|
|
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
|
-
}
|
|
1135
1083
|
|
|
1136
1084
|
class FieldSubmitState {
|
|
1137
1085
|
node;
|
|
@@ -1168,9 +1116,7 @@ class FieldNode {
|
|
|
1168
1116
|
return this._context ??= new FieldNodeContext(this);
|
|
1169
1117
|
}
|
|
1170
1118
|
fieldProxy = new Proxy(() => this, FIELD_PROXY_HANDLER);
|
|
1171
|
-
pathNode;
|
|
1172
1119
|
constructor(options) {
|
|
1173
|
-
this.pathNode = options.pathNode;
|
|
1174
1120
|
this.fieldAdapter = options.fieldAdapter;
|
|
1175
1121
|
this.structure = this.fieldAdapter.createStructure(this, options);
|
|
1176
1122
|
this.validationState = this.fieldAdapter.createValidationState(this, options);
|
|
@@ -1245,23 +1191,26 @@ class FieldNode {
|
|
|
1245
1191
|
get name() {
|
|
1246
1192
|
return this.nodeState.name;
|
|
1247
1193
|
}
|
|
1194
|
+
metadataOrUndefined(key) {
|
|
1195
|
+
return this.hasMetadata(key) ? this.metadata(key) : undefined;
|
|
1196
|
+
}
|
|
1248
1197
|
get max() {
|
|
1249
|
-
return this.
|
|
1198
|
+
return this.metadataOrUndefined(MAX);
|
|
1250
1199
|
}
|
|
1251
1200
|
get maxLength() {
|
|
1252
|
-
return this.
|
|
1201
|
+
return this.metadataOrUndefined(MAX_LENGTH);
|
|
1253
1202
|
}
|
|
1254
1203
|
get min() {
|
|
1255
|
-
return this.
|
|
1204
|
+
return this.metadataOrUndefined(MIN);
|
|
1256
1205
|
}
|
|
1257
1206
|
get minLength() {
|
|
1258
|
-
return this.
|
|
1207
|
+
return this.metadataOrUndefined(MIN_LENGTH);
|
|
1259
1208
|
}
|
|
1260
1209
|
get pattern() {
|
|
1261
|
-
return this.
|
|
1210
|
+
return this.metadataOrUndefined(PATTERN) ?? EMPTY;
|
|
1262
1211
|
}
|
|
1263
1212
|
get required() {
|
|
1264
|
-
return this.
|
|
1213
|
+
return this.metadataOrUndefined(REQUIRED) ?? FALSE;
|
|
1265
1214
|
}
|
|
1266
1215
|
metadata(key) {
|
|
1267
1216
|
return this.metadataState.get(key);
|
|
@@ -1281,7 +1230,7 @@ class FieldNode {
|
|
|
1281
1230
|
untracked(() => this._reset(value));
|
|
1282
1231
|
}
|
|
1283
1232
|
_reset(value) {
|
|
1284
|
-
if (value
|
|
1233
|
+
if (value) {
|
|
1285
1234
|
this.value.set(value);
|
|
1286
1235
|
}
|
|
1287
1236
|
this.nodeState.markAsUntouched();
|
|
@@ -1317,28 +1266,11 @@ class FieldNode {
|
|
|
1317
1266
|
static newRoot(fieldManager, value, pathNode, adapter) {
|
|
1318
1267
|
return adapter.newRoot(fieldManager, value, pathNode, adapter);
|
|
1319
1268
|
}
|
|
1269
|
+
static newChild(options) {
|
|
1270
|
+
return options.fieldAdapter.newChild(options);
|
|
1271
|
+
}
|
|
1320
1272
|
createStructure(options) {
|
|
1321
|
-
return options.kind === 'root' ? new RootFieldNodeStructure(this, options.logic, options.fieldManager, options.value,
|
|
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
|
-
});
|
|
1273
|
+
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);
|
|
1342
1274
|
}
|
|
1343
1275
|
}
|
|
1344
1276
|
const EMPTY = computed(() => [], ...(ngDevMode ? [{
|
|
@@ -1376,13 +1308,13 @@ class FieldNodeState {
|
|
|
1376
1308
|
}
|
|
1377
1309
|
dirty = computed(() => {
|
|
1378
1310
|
const selfDirtyValue = this.selfDirty() && !this.isNonInteractive();
|
|
1379
|
-
return this.node
|
|
1311
|
+
return reduceChildren(this.node, selfDirtyValue, (child, value) => value || child.nodeState.dirty(), shortCircuitTrue);
|
|
1380
1312
|
}, ...(ngDevMode ? [{
|
|
1381
1313
|
debugName: "dirty"
|
|
1382
1314
|
}] : []));
|
|
1383
1315
|
touched = computed(() => {
|
|
1384
1316
|
const selfTouchedValue = this.selfTouched() && !this.isNonInteractive();
|
|
1385
|
-
return this.node
|
|
1317
|
+
return reduceChildren(this.node, selfTouchedValue, (child, value) => value || child.nodeState.touched(), shortCircuitTrue);
|
|
1386
1318
|
}, ...(ngDevMode ? [{
|
|
1387
1319
|
debugName: "touched"
|
|
1388
1320
|
}] : []));
|
|
@@ -1408,8 +1340,8 @@ class FieldNodeState {
|
|
|
1408
1340
|
debugName: "name"
|
|
1409
1341
|
}] : []));
|
|
1410
1342
|
debouncer = computed(() => {
|
|
1411
|
-
if (this.node.logicNode.logic.
|
|
1412
|
-
const debouncerLogic = this.node.logicNode.logic.
|
|
1343
|
+
if (this.node.logicNode.logic.hasAggregateMetadata(DEBOUNCER)) {
|
|
1344
|
+
const debouncerLogic = this.node.logicNode.logic.getAggregateMetadata(DEBOUNCER);
|
|
1413
1345
|
const debouncer = debouncerLogic.compute(this.node.context);
|
|
1414
1346
|
if (debouncer) {
|
|
1415
1347
|
return signal => debouncer(this.node.context, signal);
|
|
@@ -1574,5 +1506,5 @@ function markAllAsTouched(node) {
|
|
|
1574
1506
|
}
|
|
1575
1507
|
}
|
|
1576
1508
|
|
|
1577
|
-
export { BasicFieldAdapter, DEBOUNCER, FieldNode, FieldNodeState, FieldNodeStructure, FieldPathNode, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MetadataKey,
|
|
1509
|
+
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 };
|
|
1578
1510
|
//# sourceMappingURL=_structure-chunk.mjs.map
|