MCPcopy Index your code
hub / github.com/angular/angular / FieldNodeContext

Class FieldNodeContext

packages/forms/signals/src/field/context.ts:37–180  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

35 * `FieldContext` implementation, backed by a `FieldNode`.
36 */
37export class FieldNodeContext implements FieldContext<unknown> {
38 /**
39 * Cache of paths that have been resolved for this context.
40 *
41 * For each resolved path we keep track of a signal of field that it maps to rather than a static
42 * field, since it theoretically could change. In practice for the current system it should not
43 * actually change, as they only place we currently track fields moving within the parent
44 * structure is for arrays, and paths do not currently support array indexing.
45 */
46 private readonly cache = new WeakMap<
47 SchemaPath<unknown, SchemaPathRules>,
48 Signal<ReadonlyFieldTree<unknown>>
49 >();
50
51 constructor(
52 /** The field node this context corresponds to. */
53 private readonly node: FieldNode,
54 ) {
55 // These methods are explicitly bound to the context instance so that they
56 // safely retain their `this` reference if destructured by consumers
57 // (e.g., during validation when `stateOf` or `fieldTreeOf` are extracted).
58 this.fieldTreeOf = this.fieldTreeOf.bind(this);
59 this.stateOf = this.stateOf.bind(this);
60 }
61
62 /**
63 * Resolves a target path relative to this context.
64 * @param target The path to resolve
65 * @returns The field corresponding to the target path.
66 */
67 private resolve<U>(target: SchemaPath<U, SchemaPathRules>): ReadonlyFieldTree<U> {
68 if (!this.cache.has(target)) {
69 const resolver = computed<ReadonlyFieldTree<unknown>>(() => {
70 const targetPathNode = FieldPathNode.unwrapFieldPath(target);
71
72 // First, find the field where the root our target path was merged in.
73 // We determine this by walking up the field tree from the current field and looking for
74 // the place where the LogicNodeBuilder from the target path's root was merged in.
75 // We always make sure to walk up at least as far as the depth of the path we were bound to.
76 // This ensures that we do not accidentally match on the wrong application of a recursively
77 // applied schema.
78 let field: FieldNode | undefined = this.node;
79 let stepsRemaining = getBoundPathDepth();
80 while (stepsRemaining > 0 || !field.structure.logic.hasLogic(targetPathNode.root.builder)) {
81 stepsRemaining--;
82 field = field.structure.parent;
83 if (field === undefined) {
84 throw new RuntimeError(
85 RuntimeErrorCode.PATH_NOT_IN_FIELD_TREE,
86 ngDevMode && 'Path is not part of this field tree.',
87 );
88 }
89 }
90
91 // Now, we can navigate to the target field using the relative path in the target path node
92 // to traverse down from the field we just found.
93 for (let key of targetPathNode.keys) {
94 field = field.structure.getChild(key);

Callers

nothing calls this directly

Calls 6

keyMethod · 0.95
resolveMethod · 0.95
computedFunction · 0.90
isArrayFunction · 0.90
untrackedFunction · 0.90
valueMethod · 0.65

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…