<commit_before>import { Subject } from 'rxjs/Subject';

import { Model } from './model';
import { Lifecycle, HasViewModel } from './view';
import { whenArray } from './when';
import * as LRU from 'lru-cache';

const d = require('debug')('trickline-test:collection-view');

export class ViewModelListHelper<T extends Model, P extends HasViewModel<T>, S> {
  readonly shouldRender: Subject<void>;

  private readonly keySelector: ((item: any) => string);
  private readonly viewModelCache: LRU.Cache<Model>;
  private readonly createViewModel: ((x: any, i: number) => Model);
  private currentItems: any[];

  constructor(
      lifecycle: Lifecycle<P, S>,
      props: P,
      itemsSelector: ((x: T) => any[]),
      keySelector: ((x: any) => string),
      createViewModel: ((x: any) => Model),
      lruOpts?: LRU.Options<Model>) {
    this.shouldRender = new Subject<void>();
    this.keySelector = keySelector;
    this.createViewModel = createViewModel;

    let opts = lruOpts || {max: 100};

    if (opts.dispose) {
      throw new Error("Don't set dispose, use the evicted observable");
    }

    opts.dispose = (_k: string, v: Model) => { v.unsubscribe(); };
    this.viewModelCache = LRU<Model>(opts);

    let initialVm = props.viewModel;
    let sub = lifecycle.willMount.map(() => ({ viewModel: initialVm })).concat(lifecycle.willReceiveProps)
      .switchMap(p => whenArray(p.viewModel, itemsSelector))
      .subscribe(v => {
        this.currentItems = v.value;
        this.shouldRender.next();
      });

    lifecycle.willUnmount.subscribe(() => {
      this.viewModelCache.reset();
      this.shouldRender.unsubscribe();
      sub.unsubscribe();
    });
  }

  getViewModel(index: number) {
    let key = this.keySelector(this.currentItems[index]);
    let ret = this.viewModelCache.get(key);
    if (ret) return ret;

    ret = this.createViewModel(this.currentItems[index], index);
    ret.addTeardown(() => this.viewModelCache.del(key));
    this.viewModelCache.set(key, ret);

    return ret;
  }

  getRowCount() {
    if (!this.currentItems) return 0;
    return this.currentItems.length;
  }
}<commit_msg>willMount => didMount, we will use the initial props for first render<commit_after>import { Subject } from 'rxjs/Subject';

import { Model } from './model';
import { Lifecycle, HasViewModel } from './view';
import { whenArray } from './when';
import * as LRU from 'lru-cache';

const d = require('debug')('trickline-test:collection-view');

export class ViewModelListHelper<T extends Model, P extends HasViewModel<T>, S> {
  readonly shouldRender: Subject<void>;

  private readonly keySelector: ((item: any) => string);
  private readonly viewModelCache: LRU.Cache<Model>;
  private readonly createViewModel: ((x: any, i: number) => Model);
  private currentItems: any[];

  constructor(
      lifecycle: Lifecycle<P, S>,
      props: P,
      itemsSelector: ((x: T) => any[]),
      keySelector: ((x: any) => string),
      createViewModel: ((x: any) => Model),
      lruOpts?: LRU.Options<Model>) {
    this.shouldRender = new Subject<void>();
    this.keySelector = keySelector;
    this.createViewModel = createViewModel;

    let opts = lruOpts || {max: 100};

    if (opts.dispose) {
      throw new Error("Don't set dispose, use the evicted observable");
    }

    opts.dispose = (_k: string, v: Model) => { v.unsubscribe(); };
    this.viewModelCache = LRU<Model>(opts);

    let initialVm = props.viewModel;
    let sub = lifecycle.didMount.map(() => ({ viewModel: initialVm })).concat(lifecycle.willReceiveProps)
      .switchMap(p => whenArray(p.viewModel, itemsSelector))
      .subscribe(v => {
        d(`Listening to new array via ${itemsSelector}`);
        this.currentItems = v.value;
        this.shouldRender.next();
      });

    lifecycle.willUnmount.subscribe(() => {
      this.viewModelCache.reset();
      this.shouldRender.unsubscribe();
      sub.unsubscribe();
    });
  }

  getViewModel(index: number) {
    let key = this.keySelector(this.currentItems[index]);
    let ret = this.viewModelCache.get(key);
    if (ret) return ret;

    ret = this.createViewModel(this.currentItems[index], index);
    ret.addTeardown(() => this.viewModelCache.del(key));
    this.viewModelCache.set(key, ret);

    return ret;
  }

  getRowCount() {
    if (!this.currentItems) return 0;
    return this.currentItems.length;
  }
}
{'fraction_non_alphanumeric': 0.1504222780187172, 'fraction_numerical': 0.0018260671079662178, 'mean_word_length': 3.5082304526748973, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 42, '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': '6931181', 'n_tokens_mistral': 1398, 'n_tokens_neox': 1337, 'n_words': 330}