<commit_before>import { hasIntersection } from '@statechart/util-set';
import createStyle from './style';

function mapToObj(map) {
  const obj = {};
  map.forEach((value, name) => {
    obj[name] = value;
  });
  return obj;
}

function mergeVars(acc, vars) {
  // TODO merge based on priority
  vars.forEach((value, key) => {
    if (!acc.has(key)) acc.set(key, value);
  });
  return acc;
}

export default function createSheet(backend, generateName) {
  const templates = [];
  const modules = new Map();
  const cssImports = [];

  function add(vars, $, name) {
    let template = modules.get($);
    if (!template) {
      template = createStyle($, generateName(name), add.bind(null, vars));
      if (name) template.name = name;
      modules.set($, template);
      templates.push(template);
    }
    template.vars.forEach((fn, varName) => {
      vars.set(varName, fn);
    });
    template.cssImports.forEach((i) => {
      cssImports.push(`@import ${JSON.stringify(i)};\n`);
    });
    return template;
  }

  function addModules(modules) {
    const vars = new Map();
    const tmpls = new Set();
    Object
      .keys(modules)
      .forEach(k => {
        const template = add(vars, modules[k].$, k);
        tmpls.add(template);
      });
    return [tmpls, vars];
  }

  function instantiate(overrides, tmpls, parentScope) {
    const keys = new Set(overrides.keys());
    const selectAll = overrides.size === 0 //&& tmpls.size === 0;
    const instances = new Map();
    const exports = Object.assign({}, parentScope.exports);

    const selected = selectAll ?
      templates :
      templates.filter(t => tmpls.has(t) || hasIntersection(t.dependencies, keys));

    function init(template) {
      const { imports, name } = template;

      const deps = imports.map(i => instances.get(i) || parentScope._get(i));
      const i = template.init(deps);

      instances.set(template, i);

      if (name) exports[name] = mapToObj(i.exports);

      return [
        template,
        i.render,
      ];
    }

    const renderFns = selected.map(init);

    function render(acc, values, cache) {
      for (let i = 0; i < renderFns.length; i++) {
        const [ template, render ] = renderFns[i];
        const result = render(values, cache);
        let results = acc.get(template);
        if (!results) {
          results = [];
          acc.set(template, results);
        }
        results.push(result);
      }
    }

    return [
      exports,
      render,
      instances,
    ];
  }

  function createScope(parentScope, overrides, modules) {
    let childScopes = [];
    const childRules = new Map();
    let shouldPropagate = true;

    const [ tmpls, tmplVars ] = addModules(modules);
    const [ exports, render, instances ] = instantiate(overrides, tmpls, parentScope);<commit_msg>select all templates on child scopes for now<commit_after>import { hasIntersection } from '@statechart/util-set';
import createStyle from './style';

function mapToObj(map) {
  const obj = {};
  map.forEach((value, name) => {
    obj[name] = value;
  });
  return obj;
}

function mergeVars(acc, vars) {
  // TODO merge based on priority
  vars.forEach((value, key) => {
    if (!acc.has(key)) acc.set(key, value);
  });
  return acc;
}

export default function createSheet(backend, generateName) {
  const templates = [];
  const modules = new Map();
  const cssImports = [];

  function add(vars, $, name) {
    let template = modules.get($);
    if (!template) {
      template = createStyle($, generateName(name), add.bind(null, vars));
      if (name) template.name = name;
      modules.set($, template);
      templates.push(template);
    }
    template.vars.forEach((fn, varName) => {
      vars.set(varName, fn);
    });
    template.cssImports.forEach((i) => {
      cssImports.push(`@import ${JSON.stringify(i)};\n`);
    });
    return template;
  }

  function addModules(modules) {
    const vars = new Map();
    const tmpls = new Set();
    Object
      .keys(modules)
      .forEach(k => {
        const template = add(vars, modules[k].$, k);
        tmpls.add(template);
      });
    return [tmpls, vars];
  }

  function instantiate(overrides, tmpls, parentScope) {
    const keys = new Set(overrides.keys());
    const instances = new Map();
    const exports = Object.assign({}, parentScope.exports);

    function init(template) {
      const { imports, name } = template;

      const deps = imports.map(i => instances.get(i) || parentScope._get(i));
      const i = template.init(deps);

      instances.set(template, i);

      if (name) exports[name] = mapToObj(i.exports);

      return [
        template,
        i.render,
      ];
    }

    // TODO make this more efficient by selecting applicable templates only
    const renderFns = templates.map(init);

    function render(acc, values, cache) {
      for (let i = 0; i < renderFns.length; i++) {
        const [ template, render ] = renderFns[i];
        const result = render(values, cache);
        let results = acc.get(template);
        if (!results) {
          results = [];
          acc.set(template, results);
        }
        results.push(result);
      }
    }

    return [
      exports,
      render,
      instances,
    ];
  }

  function createScope(parentScope, overrides, modules) {
    let childScopes = [];
    const childRules = new Map();
    let shouldPropagate = true;

    const [ tmpls, tmplVars ] = addModules(modules);
    const [ exports, render, instances ] = instantiate(overrides, tmpls, parentScope);
{'fraction_non_alphanumeric': 0.14584837545126353, 'fraction_numerical': 0.0007220216606498195, 'mean_word_length': 2.650197628458498, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 16, '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': '3669687', 'n_tokens_mistral': 1723, 'n_tokens_neox': 1704, 'n_words': 422}