/**
 * @license Angular v21.1.4
 * (c) 2010-2026 Google LLC. https://angular.dev/
 * License: MIT
 */

import { untracked, ɵRuntimeError as _RuntimeError, computed, runInInjectionContext, Injector, linkedSignal, signal, APP_ID, effect, inject } from '@angular/core';
import { AbstractControl } from '@angular/forms';
import { SIGNAL } from '@angular/core/primitives/signals';

let boundPathDepth = 0;
function getBoundPathDepth() {
  return boundPathDepth;
}
function setBoundPathDepthForResolution(fn, depth) {
  return (...args) => {
    try {
      boundPathDepth = depth;
      return fn(...args);
    } finally {
      boundPathDepth = 0;
    }
  };
}

function shortCircuitFalse(value) {
  return !value;
}
function shortCircuitTrue(value) {
  return value;
}
function getInjectorFromOptions(options) {
  if (options.kind === 'root') {
    return options.fieldManager.injector;
  }
  return options.parent.structure.root.structure.injector;
}

function isArray(value) {
  return Array.isArray(value);
}
function isObject(value) {
  return (typeof value === 'object' || typeof value === 'function') && value != null;
}

const DYNAMIC = Symbol();
const IGNORED = Symbol();
class AbstractLogic {
  predicates;
  fns = [];
  constructor(predicates) {
    this.predicates = predicates;
  }
  push(logicFn) {
    this.fns.push(wrapWithPredicates(this.predicates, logicFn));
  }
  mergeIn(other) {
    const fns = this.predicates ? other.fns.map(fn => wrapWithPredicates(this.predicates, fn)) : other.fns;
    this.fns.push(...fns);
  }
}
class BooleanOrLogic extends AbstractLogic {
  get defaultValue() {
    return false;
  }
  compute(arg) {
    return this.fns.some(f => {
      const result = f(arg);
      return result && result !== IGNORED;
    });
  }
}
class ArrayMergeIgnoreLogic extends AbstractLogic {
  ignore;
  static ignoreNull(predicates) {
    return new ArrayMergeIgnoreLogic(predicates, e => e === null);
  }
  constructor(predicates, ignore) {
    super(predicates);
    this.ignore = ignore;
  }
  get defaultValue() {
    return [];
  }
  compute(arg) {
    return this.fns.reduce((prev, f) => {
      const value = f(arg);
      if (value === undefined || value === IGNORED) {
        return prev;
      } else if (isArray(value)) {
        return [...prev, ...(this.ignore ? value.filter(e => !this.ignore(e)) : value)];
      } else {
        if (this.ignore && this.ignore(value)) {
          return prev;
        }
        return [...prev, value];
      }
    }, []);
  }
}
class ArrayMergeLogic extends ArrayMergeIgnoreLogic {
  constructor(predicates) {
    super(predicates, undefined);
  }
}
class MetadataMergeLogic extends AbstractLogic {
  key;
  get defaultValue() {
    return this.key.reducer.getInitial();
  }
  constructor(predicates, key) {
    super(predicates);
    this.key = key;
  }
  compute(ctx) {
    if (this.fns.length === 0) {
      return this.key.reducer.getInitial();
    }
    let acc = this.key.reducer.getInitial();
    for (let i = 0; i < this.fns.length; i++) {
      const item = this.fns[i](ctx);
      if (item !== IGNORED) {
        acc = this.key.reducer.reduce(acc, item);
      }
    }
    return acc;
  }
}
function wrapWithPredicates(predicates, logicFn) {
  if (predicates.length === 0) {
    return logicFn;
  }
  return arg => {
    for (const predicate of predicates) {
      let predicateField = arg.stateOf(predicate.path);
      const depthDiff = untracked(predicateField.structure.pathKeys).length - predicate.depth;
      for (let i = 0; i < depthDiff; i++) {
        predicateField = predicateField.structure.parent;
      }
      if (!predicate.fn(predicateField.context)) {
        return IGNORED;
      }
    }
    return logicFn(arg);
  };
}
class LogicContainer {
  predicates;
  hidden;
  disabledReasons;
  readonly;
  syncErrors;
  syncTreeErrors;
  asyncErrors;
  metadata = new Map();
  constructor(predicates) {
    this.predicates = predicates;
    this.hidden = new BooleanOrLogic(predicates);
    this.disabledReasons = new ArrayMergeLogic(predicates);
    this.readonly = new BooleanOrLogic(predicates);
    this.syncErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
    this.syncTreeErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
    this.asyncErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
  }
  hasMetadata(key) {
    return this.metadata.has(key);
  }
  getMetadataKeys() {
    return this.metadata.keys();
  }
  getMetadata(key) {
    if (!this.metadata.has(key)) {
      this.metadata.set(key, new MetadataMergeLogic(this.predicates, key));
    }
    return this.metadata.get(key);
  }
  mergeIn(other) {
    this.hidden.mergeIn(other.hidden);
    this.disabledReasons.mergeIn(other.disabledReasons);
    this.readonly.mergeIn(other.readonly);
    this.syncErrors.mergeIn(other.syncErrors);
    this.syncTreeErrors.mergeIn(other.syncTreeErrors);
    this.asyncErrors.mergeIn(other.asyncErrors);
    for (const key of other.getMetadataKeys()) {
      const metadataLogic = other.metadata.get(key);
      this.getMetadata(key).mergeIn(metadataLogic);
    }
  }
}

class AbstractLogicNodeBuilder {
  depth;
  constructor(depth) {
    this.depth = depth;
  }
  build() {
    return new LeafLogicNode(this, [], 0);
  }
}
class LogicNodeBuilder extends AbstractLogicNodeBuilder {
  constructor(depth) {
    super(depth);
  }
  current;
  all = [];
  addHiddenRule(logic) {
    this.getCurrent().addHiddenRule(logic);
  }
  addDisabledReasonRule(logic) {
    this.getCurrent().addDisabledReasonRule(logic);
  }
  addReadonlyRule(logic) {
    this.getCurrent().addReadonlyRule(logic);
  }
  addSyncErrorRule(logic) {
    this.getCurrent().addSyncErrorRule(logic);
  }
  addSyncTreeErrorRule(logic) {
    this.getCurrent().addSyncTreeErrorRule(logic);
  }
  addAsyncErrorRule(logic) {
    this.getCurrent().addAsyncErrorRule(logic);
  }
  addMetadataRule(key, logic) {
    this.getCurrent().addMetadataRule(key, logic);
  }
  getChild(key) {
    if (key === DYNAMIC) {
      const children = this.getCurrent().children;
      if (children.size > (children.has(DYNAMIC) ? 1 : 0)) {
        this.current = undefined;
      }
    }
    return this.getCurrent().getChild(key);
  }
  hasLogic(builder) {
    if (this === builder) {
      return true;
    }
    return this.all.some(({
      builder: subBuilder
    }) => subBuilder.hasLogic(builder));
  }
  mergeIn(other, predicate) {
    if (predicate) {
      this.all.push({
        builder: other,
        predicate: {
          fn: setBoundPathDepthForResolution(predicate.fn, this.depth),
          path: predicate.path
        }
      });
    } else {
      this.all.push({
        builder: other
      });
    }
    this.current = undefined;
  }
  getCurrent() {
    if (this.current === undefined) {
      this.current = new NonMergeableLogicNodeBuilder(this.depth);
      this.all.push({
        builder: this.current
      });
    }
    return this.current;
  }
  static newRoot() {
    return new LogicNodeBuilder(0);
  }
}
class NonMergeableLogicNodeBuilder extends AbstractLogicNodeBuilder {
  logic = new LogicContainer([]);
  children = new Map();
  constructor(depth) {
    super(depth);
  }
  addHiddenRule(logic) {
    this.logic.hidden.push(setBoundPathDepthForResolution(logic, this.depth));
  }
  addDisabledReasonRule(logic) {
    this.logic.disabledReasons.push(setBoundPathDepthForResolution(logic, this.depth));
  }
  addReadonlyRule(logic) {
    this.logic.readonly.push(setBoundPathDepthForResolution(logic, this.depth));
  }
  addSyncErrorRule(logic) {
    this.logic.syncErrors.push(setBoundPathDepthForResolution(logic, this.depth));
  }
  addSyncTreeErrorRule(logic) {
    this.logic.syncTreeErrors.push(setBoundPathDepthForResolution(logic, this.depth));
  }
  addAsyncErrorRule(logic) {
    this.logic.asyncErrors.push(setBoundPathDepthForResolution(logic, this.depth));
  }
  addMetadataRule(key, logic) {
    this.logic.getMetadata(key).push(setBoundPathDepthForResolution(logic, this.depth));
  }
  getChild(key) {
    if (!this.children.has(key)) {
      this.children.set(key, new LogicNodeBuilder(this.depth + 1));
    }
    return this.children.get(key);
  }
  hasLogic(builder) {
    return this === builder;
  }
}
class LeafLogicNode {
  builder;
  predicates;
  depth;
  logic;
  constructor(builder, predicates, depth) {
    this.builder = builder;
    this.predicates = predicates;
    this.depth = depth;
    this.logic = builder ? createLogic(builder, predicates, depth) : new LogicContainer([]);
  }
  getChild(key) {
    const childBuilders = this.builder ? getAllChildBuilders(this.builder, key) : [];
    if (childBuilders.length === 0) {
      return new LeafLogicNode(undefined, [], this.depth + 1);
    } else if (childBuilders.length === 1) {
      const {
        builder,
        predicates
      } = childBuilders[0];
      return new LeafLogicNode(builder, [...this.predicates, ...predicates.map(p => bindLevel(p, this.depth))], this.depth + 1);
    } else {
      const builtNodes = childBuilders.map(({
        builder,
        predicates
      }) => new LeafLogicNode(builder, [...this.predicates, ...predicates.map(p => bindLevel(p, this.depth))], this.depth + 1));
      return new CompositeLogicNode(builtNodes);
    }
  }
  hasLogic(builder) {
    return this.builder?.hasLogic(builder) ?? false;
  }
}
class CompositeLogicNode {
  all;
  logic;
  constructor(all) {
    this.all = all;
    this.logic = new LogicContainer([]);
    for (const node of all) {
      this.logic.mergeIn(node.logic);
    }
  }
  getChild(key) {
    return new CompositeLogicNode(this.all.flatMap(child => child.getChild(key)));
  }
  hasLogic(builder) {
    return this.all.some(node => node.hasLogic(builder));
  }
}
function getAllChildBuilders(builder, key) {
  if (builder instanceof LogicNodeBuilder) {
    return builder.all.flatMap(({
      builder,
      predicate
    }) => {
      const children = getAllChildBuilders(builder, key);
      if (predicate) {
        return children.map(({
          builder,
          predicates
        }) => ({
          builder,
          predicates: [...predicates, predicate]
        }));
      }
      return children;
    });
  } else if (builder instanceof NonMergeableLogicNodeBuilder) {
    return [...(key !== DYNAMIC && builder.children.has(DYNAMIC) ? [{
      builder: builder.getChild(DYNAMIC),
      predicates: []
    }] : []), ...(builder.children.has(key) ? [{
      builder: builder.getChild(key),
      predicates: []
    }] : [])];
  } else {
    throw new _RuntimeError(1909, ngDevMode && 'Unknown LogicNodeBuilder type');
  }
}
function createLogic(builder, predicates, depth) {
  const logic = new LogicContainer(predicates);
  if (builder instanceof LogicNodeBuilder) {
    const builtNodes = builder.all.map(({
      builder,
      predicate
    }) => new LeafLogicNode(builder, predicate ? [...predicates, bindLevel(predicate, depth)] : predicates, depth));
    for (const node of builtNodes) {
      logic.mergeIn(node.logic);
    }
  } else if (builder instanceof NonMergeableLogicNodeBuilder) {
    logic.mergeIn(builder.logic);
  } else {
    throw new _RuntimeError(1909, ngDevMode && 'Unknown LogicNodeBuilder type');
  }
  return logic;
}
function bindLevel(predicate, depth) {
  return {
    ...predicate,
    depth: depth
  };
}

const PATH = Symbol('PATH');
class FieldPathNode {
  keys;
  parent;
  keyInParent;
  root;
  children = new Map();
  fieldPathProxy = new Proxy(this, FIELD_PATH_PROXY_HANDLER);
  logicBuilder;
  constructor(keys, root, parent, keyInParent) {
    this.keys = keys;
    this.parent = parent;
    this.keyInParent = keyInParent;
    this.root = root ?? this;
    if (!parent) {
      this.logicBuilder = LogicNodeBuilder.newRoot();
    }
  }
  get builder() {
    if (this.logicBuilder) {
      return this.logicBuilder;
    }
    return this.parent.builder.getChild(this.keyInParent);
  }
  getChild(key) {
    if (!this.children.has(key)) {
      this.children.set(key, new FieldPathNode([...this.keys, key], this.root, this, key));
    }
    return this.children.get(key);
  }
  mergeIn(other, predicate) {
    const path = other.compile();
    this.builder.mergeIn(path.builder, predicate);
  }
  static unwrapFieldPath(formPath) {
    return formPath[PATH];
  }
  static newRoot() {
    return new FieldPathNode([], undefined, undefined, undefined);
  }
}
const FIELD_PATH_PROXY_HANDLER = {
  get(node, property) {
    if (property === PATH) {
      return node;
    }
    return node.getChild(property).fieldPathProxy;
  }
};

let currentCompilingNode = undefined;
const compiledSchemas = new Map();
class SchemaImpl {
  schemaFn;
  constructor(schemaFn) {
    this.schemaFn = schemaFn;
  }
  compile() {
    if (compiledSchemas.has(this)) {
      return compiledSchemas.get(this);
    }
    const path = FieldPathNode.newRoot();
    compiledSchemas.set(this, path);
    let prevCompilingNode = currentCompilingNode;
    try {
      currentCompilingNode = path;
      this.schemaFn(path.fieldPathProxy);
    } finally {
      currentCompilingNode = prevCompilingNode;
    }
    return path;
  }
  static create(schema) {
    if (schema instanceof SchemaImpl) {
      return schema;
    }
    return new SchemaImpl(schema);
  }
  static rootCompile(schema) {
    try {
      compiledSchemas.clear();
      if (schema === undefined) {
        return FieldPathNode.newRoot();
      }
      if (schema instanceof SchemaImpl) {
        return schema.compile();
      }
      return new SchemaImpl(schema).compile();
    } finally {
      compiledSchemas.clear();
    }
  }
}
function isSchemaOrSchemaFn(value) {
  return value instanceof SchemaImpl || typeof value === 'function';
}
function assertPathIsCurrent(path) {
  if (currentCompilingNode !== FieldPathNode.unwrapFieldPath(path).root) {
    throw new _RuntimeError(1908, ngDevMode && `A FieldPath can only be used directly within the Schema that owns it, **not** outside of it or within a sub-schema.`);
  }
}

function metadata(path, key, logic) {
  assertPathIsCurrent(path);
  const pathNode = FieldPathNode.unwrapFieldPath(path);
  pathNode.builder.addMetadataRule(key, logic);
  return key;
}
const MetadataReducer = {
  list() {
    return {
      reduce: (acc, item) => item === undefined ? acc : [...acc, item],
      getInitial: () => []
    };
  },
  min() {
    return {
      reduce: (acc, item) => {
        if (acc === undefined || item === undefined) {
          return acc ?? item;
        }
        return Math.min(acc, item);
      },
      getInitial: () => undefined
    };
  },
  max() {
    return {
      reduce: (prev, next) => {
        if (prev === undefined || next === undefined) {
          return prev ?? next;
        }
        return Math.max(prev, next);
      },
      getInitial: () => undefined
    };
  },
  or() {
    return {
      reduce: (prev, next) => prev || next,
      getInitial: () => false
    };
  },
  and() {
    return {
      reduce: (prev, next) => prev && next,
      getInitial: () => true
    };
  },
  override
};
function override(getInitial) {
  return {
    reduce: (_, item) => item,
    getInitial: () => getInitial?.()
  };
}
class MetadataKey {
  reducer;
  create;
  brand;
  constructor(reducer, create) {
    this.reducer = reducer;
    this.create = create;
  }
}
function createMetadataKey(reducer) {
  return new MetadataKey(reducer ?? MetadataReducer.override());
}
function createManagedMetadataKey(create, reducer) {
  return new MetadataKey(reducer ?? MetadataReducer.override(), create);
}
const REQUIRED = createMetadataKey(MetadataReducer.or());
const MIN = createMetadataKey(MetadataReducer.max());
const MAX = createMetadataKey(MetadataReducer.min());
const MIN_LENGTH = createMetadataKey(MetadataReducer.max());
const MAX_LENGTH = createMetadataKey(MetadataReducer.min());
const PATTERN = createMetadataKey(MetadataReducer.list());

function calculateValidationSelfStatus(state) {
  if (state.errors().length > 0) {
    return 'invalid';
  }
  if (state.pending()) {
    return 'unknown';
  }
  return 'valid';
}
class FieldValidationState {
  node;
  constructor(node) {
    this.node = node;
  }
  rawSyncTreeErrors = computed(() => {
    if (this.shouldSkipValidation()) {
      return [];
    }
    return [...this.node.logicNode.logic.syncTreeErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawSyncTreeErrors() ?? [])];
  }, ...(ngDevMode ? [{
    debugName: "rawSyncTreeErrors"
  }] : []));
  syncErrors = computed(() => {
    if (this.shouldSkipValidation()) {
      return [];
    }
    return [...this.node.logicNode.logic.syncErrors.compute(this.node.context), ...this.syncTreeErrors(), ...normalizeErrors(this.node.submitState.submissionErrors())];
  }, ...(ngDevMode ? [{
    debugName: "syncErrors"
  }] : []));
  syncValid = computed(() => {
    if (this.shouldSkipValidation()) {
      return true;
    }
    return this.node.structure.reduceChildren(this.syncErrors().length === 0, (child, value) => value && child.validationState.syncValid(), shortCircuitFalse);
  }, ...(ngDevMode ? [{
    debugName: "syncValid"
  }] : []));
  syncTreeErrors = computed(() => this.rawSyncTreeErrors().filter(err => err.fieldTree === this.node.fieldProxy), ...(ngDevMode ? [{
    debugName: "syncTreeErrors"
  }] : []));
  rawAsyncErrors = computed(() => {
    if (this.shouldSkipValidation()) {
      return [];
    }
    return [...this.node.logicNode.logic.asyncErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawAsyncErrors() ?? [])];
  }, ...(ngDevMode ? [{
    debugName: "rawAsyncErrors"
  }] : []));
  asyncErrors = computed(() => {
    if (this.shouldSkipValidation()) {
      return [];
    }
    return this.rawAsyncErrors().filter(err => err === 'pending' || err.fieldTree === this.node.fieldProxy);
  }, ...(ngDevMode ? [{
    debugName: "asyncErrors"
  }] : []));
  errors = computed(() => [...this.syncErrors(), ...this.asyncErrors().filter(err => err !== 'pending')], ...(ngDevMode ? [{
    debugName: "errors"
  }] : []));
  errorSummary = computed(() => this.node.structure.reduceChildren(this.errors(), (child, result) => [...result, ...child.errorSummary()]), ...(ngDevMode ? [{
    debugName: "errorSummary"
  }] : []));
  pending = computed(() => this.node.structure.reduceChildren(this.asyncErrors().includes('pending'), (child, value) => value || child.validationState.asyncErrors().includes('pending')), ...(ngDevMode ? [{
    debugName: "pending"
  }] : []));
  status = computed(() => {
    if (this.shouldSkipValidation()) {
      return 'valid';
    }
    let ownStatus = calculateValidationSelfStatus(this);
    return this.node.structure.reduceChildren(ownStatus, (child, value) => {
      if (value === 'invalid' || child.validationState.status() === 'invalid') {
        return 'invalid';
      } else if (value === 'unknown' || child.validationState.status() === 'unknown') {
        return 'unknown';
      }
      return 'valid';
    }, v => v === 'invalid');
  }, ...(ngDevMode ? [{
    debugName: "status"
  }] : []));
  valid = computed(() => this.status() === 'valid', ...(ngDevMode ? [{
    debugName: "valid"
  }] : []));
  invalid = computed(() => this.status() === 'invalid', ...(ngDevMode ? [{
    debugName: "invalid"
  }] : []));
  shouldSkipValidation = computed(() => this.node.hidden() || this.node.disabled() || this.node.readonly(), ...(ngDevMode ? [{
    debugName: "shouldSkipValidation"
  }] : []));
}
function normalizeErrors(error) {
  if (error === undefined) {
    return [];
  }
  if (isArray(error)) {
    return error;
  }
  return [error];
}
function addDefaultField(errors, fieldTree) {
  if (isArray(errors)) {
    for (const error of errors) {
      error.fieldTree ??= fieldTree;
    }
  } else if (errors) {
    errors.fieldTree ??= fieldTree;
  }
  return errors;
}

const DEBOUNCER = createMetadataKey();

class FieldNodeContext {
  node;
  cache = new WeakMap();
  constructor(node) {
    this.node = node;
  }
  resolve(target) {
    if (!this.cache.has(target)) {
      const resolver = computed(() => {
        const targetPathNode = FieldPathNode.unwrapFieldPath(target);
        let field = this.node;
        let stepsRemaining = getBoundPathDepth();
        while (stepsRemaining > 0 || !field.structure.logic.hasLogic(targetPathNode.root.builder)) {
          stepsRemaining--;
          field = field.structure.parent;
          if (field === undefined) {
            throw new _RuntimeError(1900, ngDevMode && 'Path is not part of this field tree.');
          }
        }
        for (let key of targetPathNode.keys) {
          field = field.structure.getChild(key);
          if (field === undefined) {
            throw new _RuntimeError(1901, ngDevMode && `Cannot resolve path .${targetPathNode.keys.join('.')} relative to field ${['<root>', ...this.node.structure.pathKeys()].join('.')}.`);
          }
        }
        return field.fieldProxy;
      }, ...(ngDevMode ? [{
        debugName: "resolver"
      }] : []));
      this.cache.set(target, resolver);
    }
    return this.cache.get(target)();
  }
  get fieldTree() {
    return this.node.fieldProxy;
  }
  get state() {
    return this.node;
  }
  get value() {
    return this.node.structure.value;
  }
  get key() {
    return this.node.structure.keyInParent;
  }
  get pathKeys() {
    return this.node.structure.pathKeys;
  }
  index = computed(() => {
    const key = this.key();
    if (!isArray(untracked(this.node.structure.parent.value))) {
      throw new _RuntimeError(1906, ngDevMode && 'Cannot access index, parent field is not an array.');
    }
    return Number(key);
  }, ...(ngDevMode ? [{
    debugName: "index"
  }] : []));
  fieldTreeOf = p => this.resolve(p);
  stateOf = p => this.resolve(p)();
  valueOf = p => {
    const result = this.resolve(p)().value();
    if (result instanceof AbstractControl) {
      throw new _RuntimeError(1907, ngDevMode && `Tried to read an 'AbstractControl' value from a 'form()'. Did you mean to use 'compatForm()' instead?`);
    }
    return result;
  };
}

class FieldMetadataState {
  node;
  metadata = new Map();
  constructor(node) {
    this.node = node;
    for (const key of this.node.logicNode.logic.getMetadataKeys()) {
      if (key.create) {
        const logic = this.node.logicNode.logic.getMetadata(key);
        const result = untracked(() => runInInjectionContext(this.node.structure.injector, () => key.create(computed(() => logic.compute(this.node.context)))));
        this.metadata.set(key, result);
      }
    }
  }
  get(key) {
    if (this.has(key)) {
      if (!this.metadata.has(key)) {
        if (key.create) {
          throw new _RuntimeError(1912, ngDevMode && 'Managed metadata cannot be created lazily');
        }
        const logic = this.node.logicNode.logic.getMetadata(key);
        this.metadata.set(key, computed(() => logic.compute(this.node.context)));
      }
    }
    return this.metadata.get(key);
  }
  has(key) {
    return this.node.logicNode.logic.hasMetadata(key);
  }
}

const FIELD_PROXY_HANDLER = {
  get(getTgt, p, receiver) {
    const tgt = getTgt();
    const child = tgt.structure.getChild(p);
    if (child !== undefined) {
      return child.fieldProxy;
    }
    const value = untracked(tgt.value);
    if (isArray(value)) {
      if (p === 'length') {
        return tgt.value().length;
      }
      if (p === Symbol.iterator) {
        return () => {
          tgt.value();
          return Array.prototype[Symbol.iterator].apply(tgt.fieldProxy);
        };
      }
    }
    if (isObject(value)) {
      if (p === Symbol.iterator) {
        return function* () {
          for (const key in receiver) {
            yield [key, receiver[key]];
          }
        };
      }
    }
    return undefined;
  },
  getOwnPropertyDescriptor(getTgt, prop) {
    const value = untracked(getTgt().value);
    const desc = Reflect.getOwnPropertyDescriptor(value, prop);
    if (desc && !desc.configurable) {
      desc.configurable = true;
    }
    return desc;
  },
  ownKeys(getTgt) {
    const value = untracked(getTgt().value);
    return typeof value === 'object' && value !== null ? Reflect.ownKeys(value) : [];
  }
};

function deepSignal(source, prop) {
  const read = computed(() => source()[prop()]);
  read[SIGNAL] = source[SIGNAL];
  read.set = value => {
    source.update(current => valueForWrite(current, value, prop()));
  };
  read.update = fn => {
    read.set(fn(untracked(read)));
  };
  read.asReadonly = () => read;
  return read;
}
function valueForWrite(sourceValue, newPropValue, prop) {
  if (isArray(sourceValue)) {
    const newValue = [...sourceValue];
    newValue[prop] = newPropValue;
    return newValue;
  } else {
    return {
      ...sourceValue,
      [prop]: newPropValue
    };
  }
}

class FieldNodeStructure {
  logic;
  node;
  createChildNode;
  identitySymbol = Symbol();
  _injector = undefined;
  get injector() {
    this._injector ??= Injector.create({
      providers: [],
      parent: this.fieldManager.injector
    });
    return this._injector;
  }
  constructor(logic, node, createChildNode) {
    this.logic = logic;
    this.node = node;
    this.createChildNode = createChildNode;
  }
  children() {
    const map = this.childrenMap();
    if (map === undefined) {
      return [];
    }
    return Array.from(map.byPropertyKey.values()).map(child => untracked(child.reader));
  }
  getChild(key) {
    const strKey = key.toString();
    let reader = untracked(this.childrenMap)?.byPropertyKey.get(strKey)?.reader;
    if (!reader) {
      reader = this.createReader(strKey);
    }
    return reader();
  }
  reduceChildren(initialValue, fn, shortCircuit) {
    const map = this.childrenMap();
    if (!map) {
      return initialValue;
    }
    let value = initialValue;
    for (const child of map.byPropertyKey.values()) {
      if (shortCircuit?.(value)) {
        break;
      }
      value = fn(untracked(child.reader), value);
    }
    return value;
  }
  destroy() {
    this.injector.destroy();
  }
  createKeyInParent(options, identityInParent, initialKeyInParent) {
    if (options.kind === 'root') {
      return ROOT_KEY_IN_PARENT;
    }
    if (identityInParent === undefined) {
      const key = initialKeyInParent;
      return computed(() => {
        if (this.parent.structure.getChild(key) !== this.node) {
          throw new _RuntimeError(1902, ngDevMode && `Orphan field, looking for property '${key}' of ${getDebugName(this.parent)}`);
        }
        return key;
      });
    } else {
      let lastKnownKey = initialKeyInParent;
      return computed(() => {
        const parentValue = this.parent.structure.value();
        if (!isArray(parentValue)) {
          throw new _RuntimeError(1903, ngDevMode && `Orphan field, expected ${getDebugName(this.parent)} to be an array`);
        }
        const data = parentValue[lastKnownKey];
        if (isObject(data) && data.hasOwnProperty(this.parent.structure.identitySymbol) && data[this.parent.structure.identitySymbol] === identityInParent) {
          return lastKnownKey;
        }
        for (let i = 0; i < parentValue.length; i++) {
          const data = parentValue[i];
          if (isObject(data) && data.hasOwnProperty(this.parent.structure.identitySymbol) && data[this.parent.structure.identitySymbol] === identityInParent) {
            return lastKnownKey = i.toString();
          }
        }
        throw new _RuntimeError(1904, ngDevMode && `Orphan field, can't find element in array ${getDebugName(this.parent)}`);
      });
    }
  }
  createChildrenMap() {
    return linkedSignal({
      source: this.value,
      computation: (value, previous) => {
        if (!isObject(value)) {
          return undefined;
        }
        const prevData = previous?.value ?? {
          byPropertyKey: new Map()
        };
        let data;
        const parentIsArray = isArray(value);
        if (prevData !== undefined) {
          if (parentIsArray) {
            data = maybeRemoveStaleArrayFields(prevData, value, this.identitySymbol);
          } else {
            data = maybeRemoveStaleObjectFields(prevData, value);
          }
        }
        for (const key of Object.keys(value)) {
          let trackingKey = undefined;
          const childValue = value[key];
          if (childValue === undefined) {
            if (prevData.byPropertyKey.has(key)) {
              data ??= {
                ...prevData
              };
              data.byPropertyKey.delete(key);
            }
            continue;
          }
          if (parentIsArray && isObject(childValue) && !isArray(childValue)) {
            trackingKey = childValue[this.identitySymbol] ??= Symbol(ngDevMode ? `id:${globalId++}` : '');
          }
          let childNode;
          if (trackingKey) {
            if (!prevData.byTrackingKey?.has(trackingKey)) {
              data ??= {
                ...prevData
              };
              data.byTrackingKey ??= new Map();
              data.byTrackingKey.set(trackingKey, this.createChildNode(key, trackingKey, parentIsArray));
            }
            childNode = (data ?? prevData).byTrackingKey.get(trackingKey);
          }
          const child = prevData.byPropertyKey.get(key);
          if (child === undefined) {
            data ??= {
              ...prevData
            };
            data.byPropertyKey.set(key, {
              reader: this.createReader(key),
              node: childNode ?? this.createChildNode(key, trackingKey, parentIsArray)
            });
          } else if (childNode && childNode !== child.node) {
            data ??= {
              ...prevData
            };
            child.node = childNode;
          }
        }
        return data ?? prevData;
      }
    });
  }
  createReader(key) {
    return computed(() => this.childrenMap()?.byPropertyKey.get(key)?.node);
  }
}
class RootFieldNodeStructure extends FieldNodeStructure {
  fieldManager;
  value;
  get parent() {
    return undefined;
  }
  get root() {
    return this.node;
  }
  get pathKeys() {
    return ROOT_PATH_KEYS;
  }
  get keyInParent() {
    return ROOT_KEY_IN_PARENT;
  }
  childrenMap;
  constructor(node, logic, fieldManager, value, createChildNode) {
    super(logic, node, createChildNode);
    this.fieldManager = fieldManager;
    this.value = value;
    this.childrenMap = this.createChildrenMap();
  }
}
class ChildFieldNodeStructure extends FieldNodeStructure {
  logic;
  parent;
  root;
  pathKeys;
  keyInParent;
  value;
  childrenMap;
  get fieldManager() {
    return this.root.structure.fieldManager;
  }
  constructor(node, logic, parent, identityInParent, initialKeyInParent, createChildNode) {
    super(logic, node, createChildNode);
    this.logic = logic;
    this.parent = parent;
    this.root = this.parent.structure.root;
    this.keyInParent = this.createKeyInParent({
      kind: 'child',
      parent,
      pathNode: undefined,
      logic,
      initialKeyInParent,
      identityInParent,
      fieldAdapter: undefined
    }, identityInParent, initialKeyInParent);
    this.pathKeys = computed(() => [...parent.structure.pathKeys(), this.keyInParent()], ...(ngDevMode ? [{
      debugName: "pathKeys"
    }] : []));
    this.value = deepSignal(this.parent.structure.value, this.keyInParent);
    this.childrenMap = this.createChildrenMap();
    this.fieldManager.structures.add(this);
  }
}
let globalId = 0;
const ROOT_PATH_KEYS = computed(() => [], ...(ngDevMode ? [{
  debugName: "ROOT_PATH_KEYS"
}] : []));
const ROOT_KEY_IN_PARENT = computed(() => {
  throw new _RuntimeError(1905, ngDevMode && 'The top-level field in the form has no parent.');
}, ...(ngDevMode ? [{
  debugName: "ROOT_KEY_IN_PARENT"
}] : []));
function getDebugName(node) {
  return `<root>.${node.structure.pathKeys().join('.')}`;
}
function maybeRemoveStaleArrayFields(prevData, value, identitySymbol) {
  let data;
  const oldKeys = new Set(prevData.byPropertyKey.keys());
  const oldTracking = new Set(prevData.byTrackingKey?.keys());
  for (let i = 0; i < value.length; i++) {
    const childValue = value[i];
    oldKeys.delete(i.toString());
    if (isObject(childValue) && childValue.hasOwnProperty(identitySymbol)) {
      oldTracking.delete(childValue[identitySymbol]);
    }
  }
  if (oldKeys.size > 0) {
    data ??= {
      ...prevData
    };
    for (const key of oldKeys) {
      data.byPropertyKey.delete(key);
    }
  }
  if (oldTracking.size > 0) {
    data ??= {
      ...prevData
    };
    for (const id of oldTracking) {
      data.byTrackingKey?.delete(id);
    }
  }
  return data;
}
function maybeRemoveStaleObjectFields(prevData, value) {
  let data;
  for (const key of prevData.byPropertyKey.keys()) {
    if (!value.hasOwnProperty(key)) {
      data ??= {
        ...prevData
      };
      data.byPropertyKey.delete(key);
    }
  }
  return data;
}

class FieldSubmitState {
  node;
  selfSubmitting = signal(false, ...(ngDevMode ? [{
    debugName: "selfSubmitting"
  }] : []));
  submissionErrors;
  constructor(node) {
    this.node = node;
    this.submissionErrors = linkedSignal({
      ...(ngDevMode ? {
        debugName: "submissionErrors"
      } : {}),
      source: this.node.structure.value,
      computation: () => []
    });
  }
  submitting = computed(() => {
    return this.selfSubmitting() || (this.node.structure.parent?.submitting() ?? false);
  }, ...(ngDevMode ? [{
    debugName: "submitting"
  }] : []));
}

class FieldNode {
  structure;
  validationState;
  metadataState;
  nodeState;
  submitState;
  fieldAdapter;
  _context = undefined;
  get context() {
    return this._context ??= new FieldNodeContext(this);
  }
  fieldProxy = new Proxy(() => this, FIELD_PROXY_HANDLER);
  pathNode;
  constructor(options) {
    this.pathNode = options.pathNode;
    this.fieldAdapter = options.fieldAdapter;
    this.structure = this.fieldAdapter.createStructure(this, options);
    this.validationState = this.fieldAdapter.createValidationState(this, options);
    this.nodeState = this.fieldAdapter.createNodeState(this, options);
    this.metadataState = new FieldMetadataState(this);
    this.submitState = new FieldSubmitState(this);
  }
  focusBoundControl() {
    this.getBindingForFocus()?.focus();
  }
  getBindingForFocus() {
    const own = this.formFieldBindings().filter(b => b.focus !== undefined).reduce(firstInDom, undefined);
    if (own) return own;
    return this.structure.children().map(child => child.getBindingForFocus()).reduce(firstInDom, undefined);
  }
  pendingSync = linkedSignal({
    ...(ngDevMode ? {
      debugName: "pendingSync"
    } : {}),
    source: () => this.value(),
    computation: (_source, previous) => {
      previous?.value?.abort();
      return undefined;
    }
  });
  get logicNode() {
    return this.structure.logic;
  }
  get value() {
    return this.structure.value;
  }
  _controlValue = linkedSignal(() => this.value(), ...(ngDevMode ? [{
    debugName: "_controlValue"
  }] : []));
  get controlValue() {
    return this._controlValue.asReadonly();
  }
  get keyInParent() {
    return this.structure.keyInParent;
  }
  get errors() {
    return this.validationState.errors;
  }
  get errorSummary() {
    return this.validationState.errorSummary;
  }
  get pending() {
    return this.validationState.pending;
  }
  get valid() {
    return this.validationState.valid;
  }
  get invalid() {
    return this.validationState.invalid;
  }
  get dirty() {
    return this.nodeState.dirty;
  }
  get touched() {
    return this.nodeState.touched;
  }
  get disabled() {
    return this.nodeState.disabled;
  }
  get disabledReasons() {
    return this.nodeState.disabledReasons;
  }
  get hidden() {
    return this.nodeState.hidden;
  }
  get readonly() {
    return this.nodeState.readonly;
  }
  get formFieldBindings() {
    return this.nodeState.formFieldBindings;
  }
  get submitting() {
    return this.submitState.submitting;
  }
  get name() {
    return this.nodeState.name;
  }
  get max() {
    return this.metadata(MAX);
  }
  get maxLength() {
    return this.metadata(MAX_LENGTH);
  }
  get min() {
    return this.metadata(MIN);
  }
  get minLength() {
    return this.metadata(MIN_LENGTH);
  }
  get pattern() {
    return this.metadata(PATTERN) ?? EMPTY;
  }
  get required() {
    return this.metadata(REQUIRED) ?? FALSE;
  }
  metadata(key) {
    return this.metadataState.get(key);
  }
  hasMetadata(key) {
    return this.metadataState.has(key);
  }
  markAsTouched() {
    untracked(() => {
      this.nodeState.markAsTouched();
      this.flushSync();
    });
  }
  markAsDirty() {
    this.nodeState.markAsDirty();
  }
  reset(value) {
    untracked(() => this._reset(value));
  }
  _reset(value) {
    if (value !== undefined) {
      this.value.set(value);
    }
    this.nodeState.markAsUntouched();
    this.nodeState.markAsPristine();
    for (const child of this.structure.children()) {
      child._reset();
    }
  }
  setControlValue(newValue) {
    untracked(() => {
      this._controlValue.set(newValue);
      this.markAsDirty();
      this.debounceSync();
    });
  }
  sync() {
    this.value.set(this.controlValue());
  }
  flushSync() {
    const pending = this.pendingSync();
    if (pending && !pending.signal.aborted) {
      pending.abort();
      this.sync();
    }
  }
  async debounceSync() {
    this.pendingSync()?.abort();
    const debouncer = this.nodeState.debouncer();
    if (debouncer) {
      const controller = new AbortController();
      const promise = debouncer(controller.signal);
      if (promise) {
        this.pendingSync.set(controller);
        await promise;
        if (controller.signal.aborted) {
          return;
        }
      }
    }
    this.sync();
  }
  static newRoot(fieldManager, value, pathNode, adapter) {
    return adapter.newRoot(fieldManager, value, pathNode, adapter);
  }
  createStructure(options) {
    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));
  }
  newChild(key, trackingId, isArray) {
    let childPath;
    let childLogic;
    if (isArray) {
      childPath = this.pathNode.getChild(DYNAMIC);
      childLogic = this.structure.logic.getChild(DYNAMIC);
    } else {
      childPath = this.pathNode.getChild(key);
      childLogic = this.structure.logic.getChild(key);
    }
    return this.fieldAdapter.newChild({
      kind: 'child',
      parent: this,
      pathNode: childPath,
      logic: childLogic,
      initialKeyInParent: key,
      identityInParent: trackingId,
      fieldAdapter: this.fieldAdapter
    });
  }
}
const EMPTY = computed(() => [], ...(ngDevMode ? [{
  debugName: "EMPTY"
}] : []));
const FALSE = computed(() => false, ...(ngDevMode ? [{
  debugName: "FALSE"
}] : []));
function firstInDom(a, b) {
  if (!a) return b;
  if (!b) return a;
  const position = a.element.compareDocumentPosition(b.element);
  return position & Node.DOCUMENT_POSITION_PRECEDING ? b : a;
}

class FieldNodeState {
  node;
  selfTouched = signal(false, ...(ngDevMode ? [{
    debugName: "selfTouched"
  }] : []));
  selfDirty = signal(false, ...(ngDevMode ? [{
    debugName: "selfDirty"
  }] : []));
  markAsTouched() {
    this.selfTouched.set(true);
  }
  markAsDirty() {
    this.selfDirty.set(true);
  }
  markAsPristine() {
    this.selfDirty.set(false);
  }
  markAsUntouched() {
    this.selfTouched.set(false);
  }
  formFieldBindings = signal([], ...(ngDevMode ? [{
    debugName: "formFieldBindings"
  }] : []));
  constructor(node) {
    this.node = node;
  }
  dirty = computed(() => {
    const selfDirtyValue = this.selfDirty() && !this.isNonInteractive();
    return this.node.structure.reduceChildren(selfDirtyValue, (child, value) => value || child.nodeState.dirty(), shortCircuitTrue);
  }, ...(ngDevMode ? [{
    debugName: "dirty"
  }] : []));
  touched = computed(() => {
    const selfTouchedValue = this.selfTouched() && !this.isNonInteractive();
    return this.node.structure.reduceChildren(selfTouchedValue, (child, value) => value || child.nodeState.touched(), shortCircuitTrue);
  }, ...(ngDevMode ? [{
    debugName: "touched"
  }] : []));
  disabledReasons = computed(() => [...(this.node.structure.parent?.nodeState.disabledReasons() ?? []), ...this.node.logicNode.logic.disabledReasons.compute(this.node.context)], ...(ngDevMode ? [{
    debugName: "disabledReasons"
  }] : []));
  disabled = computed(() => !!this.disabledReasons().length, ...(ngDevMode ? [{
    debugName: "disabled"
  }] : []));
  readonly = computed(() => (this.node.structure.parent?.nodeState.readonly() || this.node.logicNode.logic.readonly.compute(this.node.context)) ?? false, ...(ngDevMode ? [{
    debugName: "readonly"
  }] : []));
  hidden = computed(() => (this.node.structure.parent?.nodeState.hidden() || this.node.logicNode.logic.hidden.compute(this.node.context)) ?? false, ...(ngDevMode ? [{
    debugName: "hidden"
  }] : []));
  name = computed(() => {
    const parent = this.node.structure.parent;
    if (!parent) {
      return this.node.structure.fieldManager.rootName;
    }
    return `${parent.name()}.${this.node.structure.keyInParent()}`;
  }, ...(ngDevMode ? [{
    debugName: "name"
  }] : []));
  debouncer = computed(() => {
    if (this.node.logicNode.logic.hasMetadata(DEBOUNCER)) {
      const debouncerLogic = this.node.logicNode.logic.getMetadata(DEBOUNCER);
      const debouncer = debouncerLogic.compute(this.node.context);
      if (debouncer) {
        return signal => debouncer(this.node.context, signal);
      }
    }
    return this.node.structure.parent?.nodeState.debouncer?.();
  }, ...(ngDevMode ? [{
    debugName: "debouncer"
  }] : []));
  isNonInteractive = computed(() => this.hidden() || this.disabled() || this.readonly(), ...(ngDevMode ? [{
    debugName: "isNonInteractive"
  }] : []));
}

class BasicFieldAdapter {
  newRoot(fieldManager, value, pathNode, adapter) {
    return new FieldNode({
      kind: 'root',
      fieldManager,
      value,
      pathNode,
      logic: pathNode.builder.build(),
      fieldAdapter: adapter
    });
  }
  newChild(options) {
    return new FieldNode(options);
  }
  createNodeState(node) {
    return new FieldNodeState(node);
  }
  createValidationState(node) {
    return new FieldValidationState(node);
  }
  createStructure(node, options) {
    return node.createStructure(options);
  }
}

class FormFieldManager {
  injector;
  rootName;
  constructor(injector, rootName) {
    this.injector = injector;
    this.rootName = rootName ?? `${this.injector.get(APP_ID)}.form${nextFormId++}`;
  }
  structures = new Set();
  createFieldManagementEffect(root) {
    effect(() => {
      const liveStructures = new Set();
      this.markStructuresLive(root, liveStructures);
      for (const structure of this.structures) {
        if (!liveStructures.has(structure)) {
          this.structures.delete(structure);
          untracked(() => structure.destroy());
        }
      }
    }, {
      injector: this.injector
    });
  }
  markStructuresLive(structure, liveStructures) {
    liveStructures.add(structure);
    for (const child of structure.children()) {
      this.markStructuresLive(child.structure, liveStructures);
    }
  }
}
let nextFormId = 0;

function normalizeFormArgs(args) {
  let model;
  let schema;
  let options;
  if (args.length === 3) {
    [model, schema, options] = args;
  } else if (args.length === 2) {
    if (isSchemaOrSchemaFn(args[1])) {
      [model, schema] = args;
    } else {
      [model, options] = args;
    }
  } else {
    [model] = args;
  }
  return [model, schema, options];
}

function form(...args) {
  const [model, schema, options] = normalizeFormArgs(args);
  const injector = options?.injector ?? inject(Injector);
  const pathNode = runInInjectionContext(injector, () => SchemaImpl.rootCompile(schema));
  const fieldManager = new FormFieldManager(injector, options?.name);
  const adapter = options?.adapter ?? new BasicFieldAdapter();
  const fieldRoot = FieldNode.newRoot(fieldManager, model, pathNode, adapter);
  fieldManager.createFieldManagementEffect(fieldRoot.structure);
  return fieldRoot.fieldProxy;
}
function applyEach(path, schema) {
  assertPathIsCurrent(path);
  const elementPath = FieldPathNode.unwrapFieldPath(path).getChild(DYNAMIC).fieldPathProxy;
  apply(elementPath, schema);
}
function apply(path, schema) {
  assertPathIsCurrent(path);
  const pathNode = FieldPathNode.unwrapFieldPath(path);
  pathNode.mergeIn(SchemaImpl.create(schema));
}
function applyWhen(path, logic, schema) {
  assertPathIsCurrent(path);
  const pathNode = FieldPathNode.unwrapFieldPath(path);
  pathNode.mergeIn(SchemaImpl.create(schema), {
    fn: logic,
    path
  });
}
function applyWhenValue(path, predicate, schema) {
  applyWhen(path, ({
    value
  }) => predicate(value()), schema);
}
async function submit(form, action) {
  const node = form();
  const invalid = untracked(() => {
    markAllAsTouched(node);
    return node.invalid();
  });
  if (invalid) {
    return;
  }
  node.submitState.selfSubmitting.set(true);
  try {
    const errors = await action(form);
    errors && setSubmissionErrors(node, errors);
  } finally {
    node.submitState.selfSubmitting.set(false);
  }
}
function setSubmissionErrors(submittedField, errors) {
  if (!isArray(errors)) {
    errors = [errors];
  }
  const errorsByField = new Map();
  for (const error of errors) {
    const errorWithField = addDefaultField(error, submittedField.fieldProxy);
    const field = errorWithField.fieldTree();
    let fieldErrors = errorsByField.get(field);
    if (!fieldErrors) {
      fieldErrors = [];
      errorsByField.set(field, fieldErrors);
    }
    fieldErrors.push(errorWithField);
  }
  for (const [field, fieldErrors] of errorsByField) {
    field.submitState.submissionErrors.set(fieldErrors);
  }
}
function schema(fn) {
  return SchemaImpl.create(fn);
}
function markAllAsTouched(node) {
  if (node.validationState.shouldSkipValidation()) {
    return;
  }
  node.markAsTouched();
  for (const child of node.structure.children()) {
    markAllAsTouched(child);
  }
}

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, metadata, normalizeFormArgs, schema, submit };
//# sourceMappingURL=_structure-chunk.mjs.map
