<commit_before>var path = require('path');
var at = require('../../ast').js;
var html_at = require('../../ast').html;
var MERGE = false;

module.exports = function(flow){

  var packages = flow.js.packages;
  var queue = flow.files.queue;
  var fconsole = flow.console;

  // create package files
  //["dot",["name","this"],"__resource__"]

  // build source map
  var basisFile = flow.js.basisScript && flow.files.get(flow.js.basisScript);

  if (basisFile)
  {
    // inject resources
    var inserted = false;
    var resourceToc = [];

    fconsole.start('Build resource map');
    var resourceAst = (function(){
      var res = [];
      //var stat = {};
      var resourceTypeWeight = {
        'json': 1,
        'template': 2,
        'l10n': 3,
        'script': 100
      };

      for (var jsRef in flow.js.resourceMap)
      {
        var file = flow.js.resourceMap[jsRef];
        var ast = file.type == 'script' && file.ast ? file.ast[1][0] : null;

        // if (!file.jsRefCount && file.type == 'template')
        // {
        //   fconsole.log('[i] Drop resource:', file.relpath);
        //   continue;
        // }

        if (!ast)
        {
          var content = file.jsResourceContent != null
            ? file.jsResourceContent
            : file.outputContent || file.content;

          switch (typeof content)
          {
            case 'string':
              ast = ['string', content];
              break;
            default:
              if (typeof content == 'function')
                content = content.toString().replace(/function\s+anonymous/, 'function');
              else
                content = JSON.stringify(content);

              ast = at.parse('0,' + content, true)[2];
          }
        }

        // if (!stat[file.type])
        //   stat[file.type] = { count: 0, size: 0 };

        // stat[file.type].count++;
        // stat[file.type].size += content.length;

        res.push({
          relpath: file.relpath,
          type: file.type,
          ref: file.jsRef,
          ast: ast
        });
      }

      // fconsole.start('Stat:');
      // for (var type in stat)
      //   fconsole.log('[' + type + '] ' + stat[type].size + ' bytes in ' + stat[type].count + ' resource(s)');
      // fconsole.end();

      res = ['object', res.sort(function(a, b){
        var wa = resourceTypeWeight[a.type] || 0;
        var wb = resourceTypeWeight[b.type] || 0;
        return wa > wb ? 1 : (wa < wb ? -1 : 0);
      }).map(function(item){
        resourceToc.push('[' + (item.ast[0] || 'unknown') + '] ' + item.relpath + ' -> ' + item.ref);
        return [item.ref, item.ast];
      })];

      return res;
    })();
    fconsole.endl();

    fconsole.start('Inject resource map');
    if (flow.js.oldBasis)
    {
      basisFile.ast = at.walk(basisFile.ast, {
        'dot': function(token){
          var expr = token[1];
          var isRequiredHost = token[1][0] == 'name' && (token[1][1] == 'this' || token[1][1] == '__local6' || this.scope.resolve(token[1]) === this.scope.root.get('global'));

          // this.__resources__ || global.__resources__
          if (!inserted && isRequiredHost && token[2] == '__resources__')
          {
            inserted = true;
            return resourceAst;
          }
        }
      });
    }
    else
    {
      var stat = at.parse('var __resources__ = {};');
      stat[1][0][1][0][1] = resourceAst; // replace {} for resource map
      at.prepend(basisFile.ast, stat);

      if (basisFile.config.noConflict)
      {
        var rootNamespaces = Object.keys(flow.js.rootNSFile).filter(function(name){ return name != 'basis'; });
        if (rootNamespaces.length)
        {
          fconsole.start('Inject noConflict namespaces: ' + rootNamespaces);

          fconsole.log('Patch getRootNamespace');
          var getRootNamespaceToken = basisFile.jsScope.get('getRootNamespace').token;
          var getRootNamespaceFirstArg = getRootNamespaceToken[2][0];

          var rootNsAssignCode = at.parse(rootNamespaces.map(function(name){
            return 'if (' + getRootNamespaceFirstArg + ' == "' + name + '" && !' + name + ')' +
              name + ' = namespaces[' + getRootNamespaceFirstArg + '];';
          }).join(''))[1];

          Array.prototype.splice.apply(getRootNamespaceToken[3], [getRootNamespaceToken[3].length - 1, 0].concat(rootNsAssignCode));

          fconsole.log('Add root namespace declation');
          at.prepend(basisFile.ast, at.parse('var ' + rootNamespaces + ';'));

          fconsole.endl();
        }
      }
    }
    fconsole.endl();

    if (!flow.js.oldBasis && flow.js.autoload)
      // replace namespaces for it's filename in resource map
      basisFile.config.autoload = !Array.isArray(flow.js.autoload)
        // basis.js prior 1.3.0
        ? './' + flow.js.autoload.file.jsRef
        // basis.js after 1.3.0
        : flow.js.autoload.map(function(ns){
            return './' + ns.file.jsRef;
          });

    // replace config init
    fconsole.log('Replace config');
    var configToken = basisFile.jsScope.get('config').token;
    Array.prototype.splice.apply(configToken, [0, 10].concat(at.parse('0,' + JSON.stringify(basisFile.config))[1][0][1][2]));

    // inject global vars
    if (flow.js.globalVars)
      basisFile.ast[1].unshift(['var', flow.js.globalVars]);
  }

  var scriptSequenceId = basisFile ? 1 : 0;
  for (var name in packages)
  {
    var package = packages[name];

    // log package file list<commit_msg>build: fix build regression for basis.js prior 1.3.0<commit_after>var path = require('path');
var at = require('../../ast').js;
var html_at = require('../../ast').html;
var MERGE = false;

module.exports = function(flow){

  var packages = flow.js.packages;
  var queue = flow.files.queue;
  var fconsole = flow.console;

  // create package files
  //["dot",["name","this"],"__resource__"]

  // build source map
  var basisFile = flow.js.basisScript && flow.files.get(flow.js.basisScript);

  if (basisFile)
  {
    // inject resources
    var inserted = false;
    var resourceToc = [];

    fconsole.start('Build resource map');
    var resourceAst = (function(){
      var res = [];
      //var stat = {};
      var resourceTypeWeight = {
        'json': 1,
        'template': 2,
        'l10n': 3,
        'script': 100
      };

      for (var jsRef in flow.js.resourceMap)
      {
        var file = flow.js.resourceMap[jsRef];
        var ast = file.type == 'script' && file.ast ? file.ast[1][0] : null;

        // if (!file.jsRefCount && file.type == 'template')
        // {
        //   fconsole.log('[i] Drop resource:', file.relpath);
        //   continue;
        // }

        if (!ast)
        {
          var content = file.jsResourceContent != null
            ? file.jsResourceContent
            : file.outputContent || file.content;

          switch (typeof content)
          {
            case 'string':
              ast = ['string', content];
              break;
            default:
              if (typeof content == 'function')
                content = content.toString().replace(/function\s+anonymous/, 'function');
              else
                content = JSON.stringify(content);

              ast = at.parse('0,' + content, true)[2];
          }
        }

        // if (!stat[file.type])
        //   stat[file.type] = { count: 0, size: 0 };

        // stat[file.type].count++;
        // stat[file.type].size += content.length;

        res.push({
          relpath: file.relpath,
          type: file.type,
          ref: file.jsRef,
          ast: ast
        });
      }

      // fconsole.start('Stat:');
      // for (var type in stat)
      //   fconsole.log('[' + type + '] ' + stat[type].size + ' bytes in ' + stat[type].count + ' resource(s)');
      // fconsole.end();

      res = ['object', res.sort(function(a, b){
        var wa = resourceTypeWeight[a.type] || 0;
        var wb = resourceTypeWeight[b.type] || 0;
        return wa > wb ? 1 : (wa < wb ? -1 : 0);
      }).map(function(item){
        resourceToc.push('[' + (item.ast[0] || 'unknown') + '] ' + item.relpath + ' -> ' + item.ref);
        return [item.ref, item.ast];
      })];

      return res;
    })();
    fconsole.endl();

    fconsole.start('Inject resource map');
    if (flow.js.oldBasis)
    {
      basisFile.ast = at.walk(basisFile.ast, {
        'dot': function(token){
          var expr = token[1];
          var isRequiredHost = token[1][0] == 'name' && (token[1][1] == 'this' || token[1][1] == '__local6' || this.scope.resolve(token[1]) === this.scope.root.get('global'));

          // this.__resources__ || global.__resources__
          if (!inserted && isRequiredHost && token[2] == '__resources__')
          {
            inserted = true;
            return resourceAst;
          }
        }
      });
    }
    else
    {
      var stat = at.parse('var __resources__ = {};');
      stat[1][0][1][0][1] = resourceAst; // replace {} for resource map
      at.prepend(basisFile.ast, stat);

      if (basisFile.config.noConflict)
      {
        var rootNamespaces = Object.keys(flow.js.rootNSFile).filter(function(name){ return name != 'basis'; });
        if (rootNamespaces.length)
        {
          fconsole.start('Inject noConflict namespaces: ' + rootNamespaces);

          fconsole.log('Patch getRootNamespace');
          var getRootNamespaceToken = basisFile.jsScope.get('getRootNamespace').token;
          var getRootNamespaceFirstArg = getRootNamespaceToken[2][0];

          var rootNsAssignCode = at.parse(rootNamespaces.map(function(name){
            return 'if (' + getRootNamespaceFirstArg + ' == "' + name + '" && !' + name + ')' +
              name + ' = namespaces[' + getRootNamespaceFirstArg + '];';
          }).join(''))[1];

          Array.prototype.splice.apply(getRootNamespaceToken[3], [getRootNamespaceToken[3].length - 1, 0].concat(rootNsAssignCode));

          fconsole.log('Add root namespace declation');
          at.prepend(basisFile.ast, at.parse('var ' + rootNamespaces + ';'));

          fconsole.endl();
        }
      }
    }
    fconsole.endl();

    if (!flow.js.oldBasis && flow.js.autoload)
      // replace namespaces for it's filename in resource map
      basisFile.config.autoload = flow.js.autoload.file
        // basis.js prior 1.3.0
        ? './' + flow.js.autoload.file.jsRef
        // basis.js after 1.3.0
        : flow.js.autoload.map(function(ns){
            return './' + ns.file.jsRef;
          });

    // replace config init
    fconsole.log('Replace config');
    var configToken = basisFile.jsScope.get('config').token;
    Array.prototype.splice.apply(configToken, [0, 10].concat(at.parse('0,' + JSON.stringify(basisFile.config))[1][0][1][2]));

    // inject global vars
    if (flow.js.globalVars)
      basisFile.ast[1].unshift(['var', flow.js.globalVars]);
  }

  var scriptSequenceId = basisFile ? 1 : 0;
  for (var name in packages)
  {
    var package = packages[name];

    // log package file list
{'fraction_non_alphanumeric': 0.16609278724175425, 'fraction_numerical': 0.010964117433852845, 'mean_word_length': 2.0413337007440067, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '1437994', 'n_tokens_mistral': 3491, 'n_tokens_neox': 3365, 'n_words': 680}