<commit_before>import Vue, { CreateElement, VNode, VueConstructor } from 'vue';
import { isCallable, values, findIndex, warn } from '../utils';
import { ValidationResult, InactiveRefCache, VeeObserver, VNodeWithVeeContext } from '../types';
import { ValidationProvider } from './provider';
import { normalizeChildren } from '../utils/vnode';

const flagMergingStrategy: {
  [x: string]: 'every' | 'some';
} = {
  pristine: 'every',
  dirty: 'some',
  touched: 'some',
  untouched: 'every',
  valid: 'every',
  invalid: 'some',
  pending: 'some',
  validated: 'every'
};

function mergeFlags(lhs: any, rhs: any, strategy: string) {
  const stratName = flagMergingStrategy[strategy];

  return [lhs, rhs][stratName](f => f);
}

let OBSERVER_COUNTER = 0;

function data() {
  const refs: { [k: string]: InstanceType<typeof ValidationProvider> } = {};
  const inactiveRefs: { [k: string]: InactiveRefCache } = {};
  // FIXME: Not sure of this one can be typed, circular type reference.
  const observers: any[] = [];

  return {
    refs,
    observers,
    inactiveRefs
  };
}
type withObserverNode = VueConstructor<
  Vue & {
    $_veeObserver: VeeObserver;
    $vnode: VNodeWithVeeContext;
  }
>;

export const ValidationObserver = (Vue as withObserverNode).extend({
  name: 'ValidationObserver',
  provide() {
    return {
      $_veeObserver: this
    };
  },
  inject: {
    $_veeObserver: {
      from: '$_veeObserver',
      default() {
        if (!this.$vnode.context.$_veeObserver) {
          return null;
        }

        return this.$vnode.context.$_veeObserver;
      }
    }
  },
  props: {
    tag: {
      type: String,
      default: 'span'
    },
    vid: {
      type: String,
      default() {
        return `obs_${OBSERVER_COUNTER++}`;
      }
    },
    slim: {
      type: Boolean,
      default: false
    }
  },
  data,
  computed: {
    ctx() {
      const ctx = {
        errors: {},
        validate: (arg: any) => {
          const promise = this.validate(arg);

          return {
            then(thenable: { then: CallableFunction }) {
              promise.then((success: boolean) => {
                if (success && isCallable(thenable)) {
                  return Promise.resolve(thenable());
                }

                return Promise.resolve(success);
              });
            }
          };
        },
        reset: () => this.reset()
      };

      return [
        ...values(this.refs),
        ...Object.keys(this.inactiveRefs).map(key => {
          return {
            vid: key,
            flags: this.inactiveRefs[key].flags,
            messages: this.inactiveRefs[key].errors
          };
        }),
        ...this.observers
      ].reduce((acc: any, provider: any) => {
        Object.keys(flagMergingStrategy).forEach(flag => {
          const flags = provider.flags || provider.ctx;
          if (!(flag in acc)) {
            acc[flag] = flags[flag];
            return;
          }

          acc[flag] = mergeFlags(acc[flag], flags[flag], flag);<commit_msg>fix: ensure the thenable can be chained<commit_after>import Vue, { CreateElement, VNode, VueConstructor } from 'vue';
import { isCallable, values, findIndex, warn } from '../utils';
import { ValidationResult, InactiveRefCache, VeeObserver, VNodeWithVeeContext } from '../types';
import { ValidationProvider } from './provider';
import { normalizeChildren } from '../utils/vnode';

const flagMergingStrategy: {
  [x: string]: 'every' | 'some';
} = {
  pristine: 'every',
  dirty: 'some',
  touched: 'some',
  untouched: 'every',
  valid: 'every',
  invalid: 'some',
  pending: 'some',
  validated: 'every'
};

function mergeFlags(lhs: any, rhs: any, strategy: string) {
  const stratName = flagMergingStrategy[strategy];

  return [lhs, rhs][stratName](f => f);
}

let OBSERVER_COUNTER = 0;

function data() {
  const refs: { [k: string]: InstanceType<typeof ValidationProvider> } = {};
  const inactiveRefs: { [k: string]: InactiveRefCache } = {};
  // FIXME: Not sure of this one can be typed, circular type reference.
  const observers: any[] = [];

  return {
    refs,
    observers,
    inactiveRefs
  };
}
type withObserverNode = VueConstructor<
  Vue & {
    $_veeObserver: VeeObserver;
    $vnode: VNodeWithVeeContext;
  }
>;

export const ValidationObserver = (Vue as withObserverNode).extend({
  name: 'ValidationObserver',
  provide() {
    return {
      $_veeObserver: this
    };
  },
  inject: {
    $_veeObserver: {
      from: '$_veeObserver',
      default() {
        if (!this.$vnode.context.$_veeObserver) {
          return null;
        }

        return this.$vnode.context.$_veeObserver;
      }
    }
  },
  props: {
    tag: {
      type: String,
      default: 'span'
    },
    vid: {
      type: String,
      default() {
        return `obs_${OBSERVER_COUNTER++}`;
      }
    },
    slim: {
      type: Boolean,
      default: false
    }
  },
  data,
  computed: {
    ctx() {
      const ctx = {
        errors: {},
        validate: (arg: any) => {
          const promise = this.validate(arg);

          return {
            then(thenable: { then: CallableFunction }) {
              return promise.then((success: boolean) => {
                if (success && isCallable(thenable)) {
                  return Promise.resolve(thenable());
                }

                return Promise.resolve(success);
              });
            }
          };
        },
        reset: () => this.reset()
      };

      return [
        ...values(this.refs),
        ...Object.keys(this.inactiveRefs).map(key => {
          return {
            vid: key,
            flags: this.inactiveRefs[key].flags,
            messages: this.inactiveRefs[key].errors
          };
        }),
        ...this.observers
      ].reduce((acc: any, provider: any) => {
        Object.keys(flagMergingStrategy).forEach(flag => {
          const flags = provider.flags || provider.ctx;
          if (!(flag in acc)) {
            acc[flag] = flags[flag];
            return;
          }

          acc[flag] = mergeFlags(acc[flag], flags[flag], flag);
{'fraction_non_alphanumeric': 0.14501560190507473, 'fraction_numerical': 0.00032846115946789294, 'mean_word_length': 2.1489141675284387, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 21, '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': '1432186', 'n_tokens_mistral': 1881, 'n_tokens_neox': 1861, 'n_words': 418}