<commit_before>import {
  ChangeDetectorRef,
  ComponentFactory,
  ComponentFactoryResolver,
  forwardRef,
  Inject,
  Injectable,
  Injector,
  KeyValueChangeRecord,
  KeyValueChanges,
  KeyValueDiffers,
  OnDestroy,
  Optional,
  StaticProvider,
  Type,
} from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import {
  DynamicComponentInjector,
  DynamicComponentInjectorToken,
} from '../component-injector';
import { IoEventArgumentToken } from './event-argument';
import {
  IoEventContextProviderToken,
  IoEventContextToken,
} from './event-context';
import {
  AnyFunction,
  EventHandler,
  InputsType,
  OutputsType,
  OutputWithArgs,
} from './types';

interface IOMapInfo {
  propName: string;
  templateName: string;
}

type IOMappingList = IOMapInfo[];

type KeyValueChangesAny = KeyValueChanges<string, unknown>;

interface OutputsTypeProcessed extends OutputsType {
  [k: string]: EventHandler;
}

@Injectable({ providedIn: 'root' })
export class IoServiceOptions {
  trackOutputChanges = false;
}

/**
 * A provider for the {@link IoService}
 * Use it instead of manually providing a service directly
 */
export const IoServiceProvider: StaticProvider = {
  provide: forwardRef(() => IoService),
  useClass: forwardRef(() => IoService),
  deps: [
    Injector,
    KeyValueDiffers,
    ComponentFactoryResolver,
    IoServiceOptions,
    DynamicComponentInjectorToken,
    IoEventArgumentToken,
    ChangeDetectorRef,
    [new Optional(), IoEventContextProviderToken],
  ],
};

@Injectable()
export class IoService implements OnDestroy {
  private lastComponentInst: unknown = null;
  private lastChangedInputs = new Set<string>();
  private inputsDiffer = this.differs.find({}).create();
  // TODO: Replace ComponentFactory once new API is created
  // @see https://github.com/angular/angular/issues/44926
  // eslint-disable-next-line deprecation/deprecation
  private compFactory: ComponentFactory<unknown> | null = null;
  private outputsShouldDisconnect$ = new Subject<void>();
  private outputsEventContext: unknown;

  private inputs: InputsType;
  private outputs: OutputsType;
  private outputsChanged: (outputs: OutputsType) => boolean = () => false;

  private get compRef() {
    return this.compInjector.componentRef;
  }

  private get componentInst() {
    return this.compRef ? this.compRef.instance : null;
  }

  private get componentInstChanged(): boolean {
    if (this.lastComponentInst !== this.componentInst) {
      this.lastComponentInst = this.componentInst;
      return true;
    } else {
      return false;
    }
  }

  constructor(
    private injector: Injector,
    private differs: KeyValueDiffers,
    // TODO: Replace ComponentFactoryResolver once new API is created
    // @see https://github.com/angular/angular/issues/44926
    // eslint-disable-next-line deprecation/deprecation
    private cfr: ComponentFactoryResolver,
    private options: IoServiceOptions,
    @Inject(DynamicComponentInjectorToken)
    private compInjector: DynamicComponentInjector,
    @Inject(IoEventArgumentToken)
    private eventArgument: string,
    private cdr: ChangeDetectorRef,
    @Inject(IoEventContextProviderToken)
    @Optional()
    private eventContextProvider: StaticProvider,
  ) {
    if (this.options.trackOutputChanges) {
      const outputsDiffer = this.differs.find({}).create();
      this.outputsChanged = (outputs) => !!outputsDiffer.diff(outputs);
    }
  }

  ngOnDestroy(): void {
    this._disconnectOutputs();
  }

  /**
   * Call when you know that inputs/outputs were changed
   * or when setting them for the first time
   */
  update(inputs: InputsType, outputs: OutputsType) {
    const changes = this.updateIO(inputs, outputs);

    const compChanged = this.componentInstChanged;

    if (compChanged || changes.inputsChanged) {
      const inputsChanges = this._getInputsChanges();
      if (inputsChanges) {
        this._updateChangedInputs(inputsChanges);
      }
      this.updateInputs(compChanged || !this.lastChangedInputs.size);
    }

    if (compChanged || changes.outputsChanged) {
      this.bindOutputs();
    }
  }

  /**
   * Call when you do not know if inputs/outputs changed
   *
   * Usually must be called from the `DoCheck` lifecycle hook
   */
  maybeUpdate() {
    if (this.componentInstChanged) {
      this.updateInputs(true);
      this.bindOutputs();
      return;
    }

    if (this.outputsChanged(this.outputs)) {
      this.bindOutputs();
    }

    if (!this.inputs) {
      return;<commit_msg>perf(io): do not detect any changes when there is no component<commit_after>import {
  ChangeDetectorRef,
  ComponentFactory,
  ComponentFactoryResolver,
  forwardRef,
  Inject,
  Injectable,
  Injector,
  KeyValueChangeRecord,
  KeyValueChanges,
  KeyValueDiffers,
  OnDestroy,
  Optional,
  StaticProvider,
  Type,
} from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import {
  DynamicComponentInjector,
  DynamicComponentInjectorToken,
} from '../component-injector';
import { IoEventArgumentToken } from './event-argument';
import {
  IoEventContextProviderToken,
  IoEventContextToken,
} from './event-context';
import {
  AnyFunction,
  EventHandler,
  InputsType,
  OutputsType,
  OutputWithArgs,
} from './types';

interface IOMapInfo {
  propName: string;
  templateName: string;
}

type IOMappingList = IOMapInfo[];

type KeyValueChangesAny = KeyValueChanges<string, unknown>;

interface OutputsTypeProcessed extends OutputsType {
  [k: string]: EventHandler;
}

@Injectable({ providedIn: 'root' })
export class IoServiceOptions {
  trackOutputChanges = false;
}

/**
 * A provider for the {@link IoService}
 * Use it instead of manually providing a service directly
 */
export const IoServiceProvider: StaticProvider = {
  provide: forwardRef(() => IoService),
  useClass: forwardRef(() => IoService),
  deps: [
    Injector,
    KeyValueDiffers,
    ComponentFactoryResolver,
    IoServiceOptions,
    DynamicComponentInjectorToken,
    IoEventArgumentToken,
    ChangeDetectorRef,
    [new Optional(), IoEventContextProviderToken],
  ],
};

@Injectable()
export class IoService implements OnDestroy {
  private lastComponentInst: unknown = null;
  private lastChangedInputs = new Set<string>();
  private inputsDiffer = this.differs.find({}).create();
  // TODO: Replace ComponentFactory once new API is created
  // @see https://github.com/angular/angular/issues/44926
  // eslint-disable-next-line deprecation/deprecation
  private compFactory: ComponentFactory<unknown> | null = null;
  private outputsShouldDisconnect$ = new Subject<void>();
  private outputsEventContext: unknown;

  private inputs: InputsType;
  private outputs: OutputsType;
  private outputsChanged: (outputs: OutputsType) => boolean = () => false;

  private get compRef() {
    return this.compInjector.componentRef;
  }

  private get componentInst() {
    return this.compRef ? this.compRef.instance : null;
  }

  private get componentInstChanged(): boolean {
    if (this.lastComponentInst !== this.componentInst) {
      this.lastComponentInst = this.componentInst;
      return true;
    } else {
      return false;
    }
  }

  constructor(
    private injector: Injector,
    private differs: KeyValueDiffers,
    // TODO: Replace ComponentFactoryResolver once new API is created
    // @see https://github.com/angular/angular/issues/44926
    // eslint-disable-next-line deprecation/deprecation
    private cfr: ComponentFactoryResolver,
    private options: IoServiceOptions,
    @Inject(DynamicComponentInjectorToken)
    private compInjector: DynamicComponentInjector,
    @Inject(IoEventArgumentToken)
    private eventArgument: string,
    private cdr: ChangeDetectorRef,
    @Inject(IoEventContextProviderToken)
    @Optional()
    private eventContextProvider: StaticProvider,
  ) {
    if (this.options.trackOutputChanges) {
      const outputsDiffer = this.differs.find({}).create();
      this.outputsChanged = (outputs) => !!outputsDiffer.diff(outputs);
    }
  }

  ngOnDestroy(): void {
    this._disconnectOutputs();
  }

  /**
   * Call when you know that inputs/outputs were changed
   * or when setting them for the first time
   */
  update(inputs: InputsType, outputs: OutputsType) {
    if (!this.compRef) {
      return;
    }

    const changes = this.updateIO(inputs, outputs);

    const compChanged = this.componentInstChanged;

    if (compChanged || changes.inputsChanged) {
      const inputsChanges = this._getInputsChanges();
      if (inputsChanges) {
        this._updateChangedInputs(inputsChanges);
      }
      this.updateInputs(compChanged || !this.lastChangedInputs.size);
    }

    if (compChanged || changes.outputsChanged) {
      this.bindOutputs();
    }
  }

  /**
   * Call when you do not know if inputs/outputs changed
   *
   * Usually must be called from the `DoCheck` lifecycle hook
   */
  maybeUpdate() {
    if (!this.compRef) {
      this._disconnectOutputs();
      return;
    }

    if (this.componentInstChanged) {
      this.updateInputs(true);
      this.bindOutputs();
      return;
    }

    if (this.outputsChanged(this.outputs)) {
      this.bindOutputs();
    }

    if (!this.inputs) {
      return;
{'fraction_non_alphanumeric': 0.1041801335918983, 'fraction_numerical': 0.0021547080370609784, 'mean_word_length': 3.777663407102419, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4736087', 'n_tokens_mistral': 2709, 'n_tokens_neox': 2685, 'n_words': 646}