<commit_before>import {
  UIRouter, PathFactory, StateOrName, State, StateDeclaration, PathNode, TreeChanges, Transition, UIRouterPluginBase,
  TransitionHookPhase, TransitionHookScope, TransitionServicePluginAPI, HookMatchCriteria, TransitionStateHookFn,
  HookRegOptions, PathType, find, tail, isString, isArray, inArray, removeFrom, pushTo, identity, anyTrueR, assertMap,
  uniqR, defaultTransOpts, HookMatchCriterion
} from "ui-router-core";

declare module "ui-router-core/lib/state/interface" {
  interface StateDeclaration {
    sticky?: boolean;
    onInactivate?: TransitionStateHookFn;
    onReactivate?: TransitionStateHookFn;
  }
}

declare module "ui-router-core/lib/state/stateObject" {
  interface State {
    sticky?: boolean;
    onInactivate?: TransitionStateHookFn;
    onReactivate?: TransitionStateHookFn;
  }
}

declare module "ui-router-core/lib/transition/transitionService" {
  interface TransitionService {
    onInactivate: (criteria: HookMatchCriteria, callback: TransitionStateHookFn, options?: HookRegOptions) => Function;
    onReactivate: (criteria: HookMatchCriteria, callback: TransitionStateHookFn, options?: HookRegOptions) => Function;
  }
}

declare module "ui-router-core/lib/transition/interface" {
  interface TransitionOptions {
    exitSticky: StateOrName[]|StateOrName;
  }

  interface TreeChanges {
    inactivating?: PathNode[];
    reactivating?: PathNode[];
  }

  export interface IMatchingNodes {
    inactivating: PathNode[];
    reactivating: PathNode[];
  }

  export interface PathTypes {
    inactivating: PathType;
    reactivating: PathType;
  }

  export interface HookMatchCriteria {
    /** A [[HookMatchCriterion]] to match any state that would be inactivating */
    inactivating?: HookMatchCriterion;
    /** A [[HookMatchCriterion]] to match any state that would be reactivating */
    reactivating?: HookMatchCriterion;
  }
}

const notInArray = (arr: any[]) => (item) => !inArray(arr, item);

const isChildOf = (parent: PathNode) =>
    (node: PathNode) =>
    node.state.parent === parent.state;

const isChildOfAny = (_parents: PathNode[]) => {
  return (node: PathNode) =>
      _parents.map(parent => isChildOf(parent)(node)).reduce(anyTrueR, false);
};

const ancestorPath = (state: State) =>
    state.parent ? ancestorPath(state.parent).concat(state) : [state];

const isDescendantOf = (_ancestor: PathNode) => {
  let ancestor = _ancestor.state;
  return (node: PathNode) =>
  ancestorPath(node.state).indexOf(ancestor) !== -1;
};

const isDescendantOfAny = (ancestors: PathNode[]) =>
    (node: PathNode) =>
        ancestors.map(ancestor => isDescendantOf(ancestor)(node))
            .reduce(anyTrueR, false);

function findStickyAncestor(state: State) {
  return state.sticky ? state : findStickyAncestor(state.parent);
}



/**
 * Sorts fn that sorts by:
 * 1) node depth (how deep a state is nested)
 * 2) the order in which the state was inactivated (later in wins)
 */
function nodeDepthThenInactivateOrder(inactives: PathNode[]) {
  return function(l: PathNode, r: PathNode): number {
    let depthDelta = (l.state.path.length - r.state.path.length);
    return depthDelta !== 0 ? depthDelta : inactives.indexOf(r) - inactives.indexOf(l);
  };
}
export class StickyStatesPlugin extends UIRouterPluginBase {
  name = "stickystates";
  private _inactives: PathNode[] = [];
  private pluginAPI: TransitionServicePluginAPI;

  constructor(public router: UIRouter) {
    super();

    this.pluginAPI = router.transitionService._pluginapi;

    this._defineStickyPaths();
    this._defineStickyEvents();
    this._addCreateHook();
    this._addStateCallbacks();
    this._addDefaultTransitionOption();
  }

  inactives(): StateDeclaration {
    return this._inactives.map(node => node.state.self);
  }

  private _addCreateHook() {
    this.router.transitionService.onCreate({}, (trans) => {
      trans['_treeChanges'] = this._calculateStickyTreeChanges(trans);
    });
  }

  private _defineStickyPaths() {
    // let paths = this.pluginAPI._getPathTypes();
    this.pluginAPI._definePathType("inactivating", TransitionHookScope.STATE);
    this.pluginAPI._definePathType("reactivating", TransitionHookScope.STATE);
  }

  private _defineStickyEvents() {
    let paths = this.pluginAPI._getPathTypes();
    this.pluginAPI._defineEvent("onInactivate", TransitionHookPhase.ASYNC, 5, paths.inactivating, true);
    this.pluginAPI._defineEvent("onReactivate", TransitionHookPhase.ASYNC, 35, paths.reactivating);
  }

  // Process state.onInactivate or state.onReactivate callbacks
  private _addStateCallbacks() {<commit_msg>fix(sticky): Move sticky states hook to hither priority (100), so it is invoked before the transition is processed by ui-router-core `coreResolcables` onCreate hook<commit_after>import {
  UIRouter, PathFactory, StateOrName, State, StateDeclaration, PathNode, TreeChanges, Transition, UIRouterPluginBase,
  TransitionHookPhase, TransitionHookScope, TransitionServicePluginAPI, HookMatchCriteria, TransitionStateHookFn,
  HookRegOptions, PathType, find, tail, isString, isArray, inArray, removeFrom, pushTo, identity, anyTrueR, assertMap,
  uniqR, defaultTransOpts, HookMatchCriterion
} from "ui-router-core";

declare module "ui-router-core/lib/state/interface" {
  interface StateDeclaration {
    sticky?: boolean;
    onInactivate?: TransitionStateHookFn;
    onReactivate?: TransitionStateHookFn;
  }
}

declare module "ui-router-core/lib/state/stateObject" {
  interface State {
    sticky?: boolean;
    onInactivate?: TransitionStateHookFn;
    onReactivate?: TransitionStateHookFn;
  }
}

declare module "ui-router-core/lib/transition/transitionService" {
  interface TransitionService {
    onInactivate: (criteria: HookMatchCriteria, callback: TransitionStateHookFn, options?: HookRegOptions) => Function;
    onReactivate: (criteria: HookMatchCriteria, callback: TransitionStateHookFn, options?: HookRegOptions) => Function;
  }
}

declare module "ui-router-core/lib/transition/interface" {
  interface TransitionOptions {
    exitSticky: StateOrName[]|StateOrName;
  }

  interface TreeChanges {
    inactivating?: PathNode[];
    reactivating?: PathNode[];
  }

  export interface IMatchingNodes {
    inactivating: PathNode[];
    reactivating: PathNode[];
  }

  export interface PathTypes {
    inactivating: PathType;
    reactivating: PathType;
  }

  export interface HookMatchCriteria {
    /** A [[HookMatchCriterion]] to match any state that would be inactivating */
    inactivating?: HookMatchCriterion;
    /** A [[HookMatchCriterion]] to match any state that would be reactivating */
    reactivating?: HookMatchCriterion;
  }
}

const notInArray = (arr: any[]) => (item) => !inArray(arr, item);

const isChildOf = (parent: PathNode) =>
    (node: PathNode) =>
    node.state.parent === parent.state;

const isChildOfAny = (_parents: PathNode[]) => {
  return (node: PathNode) =>
      _parents.map(parent => isChildOf(parent)(node)).reduce(anyTrueR, false);
};

const ancestorPath = (state: State) =>
    state.parent ? ancestorPath(state.parent).concat(state) : [state];

const isDescendantOf = (_ancestor: PathNode) => {
  let ancestor = _ancestor.state;
  return (node: PathNode) =>
  ancestorPath(node.state).indexOf(ancestor) !== -1;
};

const isDescendantOfAny = (ancestors: PathNode[]) =>
    (node: PathNode) =>
        ancestors.map(ancestor => isDescendantOf(ancestor)(node))
            .reduce(anyTrueR, false);

function findStickyAncestor(state: State) {
  return state.sticky ? state : findStickyAncestor(state.parent);
}



/**
 * Sorts fn that sorts by:
 * 1) node depth (how deep a state is nested)
 * 2) the order in which the state was inactivated (later in wins)
 */
function nodeDepthThenInactivateOrder(inactives: PathNode[]) {
  return function(l: PathNode, r: PathNode): number {
    let depthDelta = (l.state.path.length - r.state.path.length);
    return depthDelta !== 0 ? depthDelta : inactives.indexOf(r) - inactives.indexOf(l);
  };
}
export class StickyStatesPlugin extends UIRouterPluginBase {
  name = "stickystates";
  private _inactives: PathNode[] = [];
  private pluginAPI: TransitionServicePluginAPI;

  constructor(public router: UIRouter) {
    super();

    this.pluginAPI = router.transitionService._pluginapi;

    this._defineStickyPaths();
    this._defineStickyEvents();
    this._addCreateHook();
    this._addStateCallbacks();
    this._addDefaultTransitionOption();
  }

  inactives(): StateDeclaration {
    return this._inactives.map(node => node.state.self);
  }

  private _addCreateHook() {
    this.router.transitionService.onCreate({}, (trans) => {
      trans['_treeChanges'] = this._calculateStickyTreeChanges(trans);
    }, { priority: 100 });
  }

  private _defineStickyPaths() {
    // let paths = this.pluginAPI._getPathTypes();
    this.pluginAPI._definePathType("inactivating", TransitionHookScope.STATE);
    this.pluginAPI._definePathType("reactivating", TransitionHookScope.STATE);
  }

  private _defineStickyEvents() {
    let paths = this.pluginAPI._getPathTypes();
    this.pluginAPI._defineEvent("onInactivate", TransitionHookPhase.ASYNC, 5, paths.inactivating, true);
    this.pluginAPI._defineEvent("onReactivate", TransitionHookPhase.ASYNC, 35, paths.reactivating);
  }

  // Process state.onInactivate or state.onReactivate callbacks
  private _addStateCallbacks() {
{'fraction_non_alphanumeric': 0.1186513017498933, 'fraction_numerical': 0.002134016218523261, 'mean_word_length': 4.704808277541083, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 37, 'https://': 0, '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': '468749', 'n_tokens_mistral': 2886, 'n_tokens_neox': 2805, 'n_words': 624}