<commit_before>import {
  ComponentFactory, ClassType, Component, ComponentResolver, Injectable,
  AppView, Renderer, RootRenderer, ComponentRef, ComponentFactoryResolver,
  resolveReflectiveProviders, ElementRef, Injector, ApplicationRef, Provider,
  ReflectiveInjector
} from 'mojiito-core';

import { ListWrapper } from './facade/collection';
import { stringify } from './facade/lang';
import { CssSelector, SelectorMatcher } from './selector';
import { Visitor, DomVisitor } from './dom_visitor';
import { DomRenderer } from './dom_renderer';
import { DomTraverser } from './dom_traverser';

const UNDEFINED = new Object();

export class ComponentCompiledResult<C> {
  constructor(public componentType: ClassType<C>, public viewClass: ClassType<AppView<C>>,
    public matcher: SelectorMatcher, public visitor: Visitor) { }
}

@Injectable()
export class Compiler {
  private _results = new Map<ClassType<any>, ComponentCompiledResult<any>>();

  constructor(private _resolver: ComponentResolver) { }

  get componentFactoryResolver() {
    const factories: ComponentFactory<any>[] = [];
    this._results.forEach((r, c) => {
      factories.push(new ComponentFactory(r.viewClass, c));
    });
    return new ComponentFactoryResolver(factories);
  }

  get<C>(component: ClassType<C>): ComponentCompiledResult<C> {
    return this._results.get(component);
  }

  compileComponents(components: ClassType<any>[]): ComponentCompiledResult<any>[] {
    return components.map(c => this.compileComponent(c));
  }

  compileComponent<C>(component: ClassType<C>): ComponentCompiledResult<C> {
    const metadata = this._resolver.resolve(component);
    const matcher = new SelectorMatcher();
    matcher.addSelectables(CssSelector.parse(metadata.selector));
    let injector: Injector = null;
    if (metadata.providers) {
      injector = ReflectiveInjector.resolveAndCreate(metadata.providers);
    }

    let visitor: Visitor = null;
    if (metadata.components) {
      let compiled = this.compileComponents(ListWrapper.flatten(metadata.components));
      visitor = new DomVisitor(compiled);
      compiled.forEach(c => {
        if (!c.visitor) {
          c.visitor = visitor;
        }
      });
    }
    const viewClass = this._compileView(component, injector);
    const result =
      new ComponentCompiledResult(component, viewClass, matcher, visitor);
    this._results.set(component, result);
    return result;
  }

  private _compileView<C>(component: ClassType<C>, injector: Injector): ClassType<AppView<C>> {<commit_msg>added a note for further features<commit_after>import {
  ComponentFactory, ClassType, Component, ComponentResolver, Injectable,
  AppView, Renderer, RootRenderer, ComponentRef, ComponentFactoryResolver,
  resolveReflectiveProviders, ElementRef, Injector, ApplicationRef, Provider,
  ReflectiveInjector
} from 'mojiito-core';

import { ListWrapper } from './facade/collection';
import { stringify } from './facade/lang';
import { CssSelector, SelectorMatcher } from './selector';
import { Visitor, DomVisitor } from './dom_visitor';
import { DomRenderer } from './dom_renderer';
import { DomTraverser } from './dom_traverser';

const UNDEFINED = new Object();

export class ComponentCompiledResult<C> {
  constructor(public componentType: ClassType<C>, public viewClass: ClassType<AppView<C>>,
    public matcher: SelectorMatcher, public visitor: Visitor) { }
}

@Injectable()
export class Compiler {
  private _results = new Map<ClassType<any>, ComponentCompiledResult<any>>();

  constructor(private _resolver: ComponentResolver) { }

  get componentFactoryResolver() {
    const factories: ComponentFactory<any>[] = [];
    this._results.forEach((r, c) => {
      factories.push(new ComponentFactory(r.viewClass, c));
    });
    return new ComponentFactoryResolver(factories);
  }

  get<C>(component: ClassType<C>): ComponentCompiledResult<C> {
    return this._results.get(component);
  }

  compileComponents(components: ClassType<any>[]): ComponentCompiledResult<any>[] {
    return components.map(c => this.compileComponent(c));
  }

  compileComponent<C>(component: ClassType<C>): ComponentCompiledResult<C> {
    const metadata = this._resolver.resolve(component);
    const matcher = new SelectorMatcher();
    matcher.addSelectables(CssSelector.parse(metadata.selector));
    let injector: Injector = null;
    if (metadata.providers) {
      injector = ReflectiveInjector.resolveAndCreate(metadata.providers);
    }

    // TODO
    // Always compile a visitor even if no sub components are there
    // Issue: #38
    let visitor: Visitor = null;
    if (metadata.components) {
      let compiled = this.compileComponents(ListWrapper.flatten(metadata.components));
      visitor = new DomVisitor(compiled);
      compiled.forEach(c => {
        if (!c.visitor) {
          c.visitor = visitor;
        }
      });
    }
    const viewClass = this._compileView(component, injector);
    const result =
      new ComponentCompiledResult(component, viewClass, matcher, visitor);
    this._results.set(component, result);
    return result;
  }

  private _compileView<C>(component: ClassType<C>, injector: Injector): ClassType<AppView<C>> {
{'fraction_non_alphanumeric': 0.12032394909371384, 'fraction_numerical': 0.0003856536829926726, 'mean_word_length': 4.571428571428571, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 49, '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': '7544868', 'n_tokens_mistral': 1498, 'n_tokens_neox': 1484, 'n_words': 333}