<commit_before>/**
 * @file Task基类
 * @author AceMood, XCB
 */

var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var path = require('path');

var PluginMap = require('./PluginMap');
var RuleMap = require('./RuleMap');

var RE_IMG_URL = /url\s*\(\s*(['"]?)([^"'\)]*)\1\s*\)/gi;
var RE_URL = /(?:\s*)url\((?:(?:"|')?)(?:\s*)([^\)"']*)(?:\s*)(?:(?:"|')?)\)(?:\s*)/;
var requireJsReg = /\brequire\s*\(\s*(["'])([^'"\s]+)\1\s*\)/g;
var requireAsyncJsReg = /\brequire\s*\.async\(\s*["']([^'"\s]+)["'][^\)]*\)/g;

/**
 * 冻结方法
 * @param {object} obj
 * @param {Array} props
 */
function seal(obj, props) {
  props.forEach(props, function(prop) {
    Object.defineProperty(obj, prop, {
      writable: false,
      enumerable: true,
      value: obj[prop]
    });
  });
}

/**
 * 判断给定路径是否网络绝对路径, 即http(s)://开头的路径
 * @param {string} url
 * @returns {boolean}
 */
function isAbsUrl(url) {
  return /:\//.test(url);
}

/**
 * 给模块代码加入cmd wrapper
 * @param {JSResource} jsResource
 * @param {object} options
 */
function cmdWrapper(jsResource, options) {
  /*
   jsResource.getContent().replace(/\/\*([\s\S]*?)\*\//m, function(match) {
   console.log(match);
   return match + '\n\n' + 'define(){';
   }) + '})';
   */
  var content =
      options.commentdoc + '\n' +
      options.define + '("' + jsResource.id + '", function(require, exports, module) {\n' +
      (options.usestrict ? '"use strict";' : '') +
      jsResource.getContent() + '\n});';

  jsResource.setContent(content);
}

/**
 * Task
 * @param {string}      name
 * @param {?object}     options
 * @param {?object}     soiOptions
 * @param {?object}     args
 * @param {ResourceMap} map
 * @constructor
 */
function Task(name, options, soiOptions, args, map) {
  this.name = name;
  this.rules = new RuleMap();
  this.plugins = new PluginMap();
  this.options = options;
  this.args = args; //命令行相关参数
  this.soiOptions = soiOptions;
  this.map = map;

  seal(this, [
    'addRule', 'use', 'run', 'setArgs', 'setMap', '_apply', 'config', '_mergeRule',
    'beforeCompile', 'compile', '_compileImage', '_compileCSS', '_compileJS',
    'pack', 'postProcess', 'shim', 'flush'
  ]);
}

inherits(Task, EventEmitter);

/**
 * 合并soi共用规则和当前task的规则
 */
Task.prototype._mergeRule = function() {
  this.rules.merge(soi.rules);
};

/**
 * 编译图片资源
 * @param {ImageResource} resource
 */
Task.prototype._compileImage = function(resource) {
  // 暂时不需要做什么额外的操作
  this.emit('compiled', resource);
  this.resolveProductUriInternal(resource);
  resource.isCompiled = true;
};

/**
 * 编译css资源
 * @param {CssResource} resource
 */
Task.prototype._compileCSS = function(resource) {
  var task = this;
  // 替换css中的资源, 递归编译
  resource.getContent()
      .replace(RE_URL, function($0, $1) {
        if (isAbsUrl($1)) {
          return $1;
        }

        var uri = path.resolve(resource.path, $1);
        var inlineResource = map.getResourceByPath(uri);
        // 若图片未编译
        if (inlineResource && !inlineResource.isCompiled) {
          task._compileImage(inlineResource);
          return inlineResource.uri;
        }
        // todo warning
        return $1;
      });

  this.emit('compiled', resource);
  this.resolveProductUriInternal(resource);
  resource.isCompiled = true;
};

/**
 * 编译js资源
 * @param {JSResource} resource
 */
Task.prototype._compileJS = function(resource) {
  var task = this;

  resource.getContent()
      .replace(requireJsReg, function(match, $1, $2) {
        // $2 就是匹配出来的依赖路径
        var dirName = path.parse(resource.path).dir, url;
        match = match.replace(/\s/g, '');
        url =  soi.util.normalizeSysPath(path.resolve(dirName, $2));
        var inlineResource = task.map.resourcePathMap[url];
        if (inlineResource && !inlineResource.isCompiled) {
          task._compileJS(inlineResource);
        }

        return match.replace($2, inlineResource.id);
      })
      .replace(requireAsycJsReg, function(match, dep) {
        // todo dep 是依赖数组
        var dirName = path.parse(resource.path).dir, url;
        match = match.replace(/\s/g, '');
        url =  soi.util.normalizeSysPath(path.resolve(dirName, dep));
        var inlineResource = task.map.resourcePathMap[url];
        if (inlineResource && !inlineResource.isCompiled) {
          task._compileJS(inlineResource);
        }

        return match.replace(dep, inlineResource.id);
      });

  if (resource.isModule) {
    cmdWrapper(resource, task.config.get('cmdWrapper'));
  }

  this.emit('compiled', resource);
  this.resolveProductUriInternal(resource);
  resource.isCompiled = true;
};

/**
 * 应用插件
 */
Task.prototype._apply = function() {
  this.plugins._apply(this);
  return this;
};


//===============================================
// 以下为公共API, 不可改变
//===============================================
/**
 * 设置命令行相关参数
 * @param {object} params
 * @returns {Task}
 */
Task.prototype.setArgs = function (params) {
  this.args = params;
  return this;
};

/**
 * 设置map资源表相关
 * @param {ResourceMap} map
 * @returns {Task}
 */
Task.prototype.setMap = function (map) {
  this.map = map;
  return this;
};

/**
 * 添加规则
 * @param {string|RegExp} pattern
 * @param {?object} options
 */
Task.prototype.addRule = function(pattern, options) {
  this.rules.add(pattern, options);
  return this;
};

/**
 * 记录要使用的服务插件
 * @param {string} plug
 * @param {?object} options
 * @return {Task}
 */
Task.prototype.use = function (plug, options) {
  this.plugins.add(plug, options);
  return this;
};

/**
 * 执行
 */
Task.prototype.run = function() {
  this._mergeRule();
  this._apply();
  this.emit('beforeCompile', this);
  this.beforeCompile(function() {
    this.emit('compile', this);
    // 编译
    this.compile(function() {
      this.emit('compiled', this);
      this.emit('pack', this);
      // 合并打包
      this.pack(function() {<commit_msg>modify event name<commit_after>/**
 * @file Task基类
 * @author AceMood, XCB
 */

var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var path = require('path');

var PluginMap = require('./PluginMap');
var RuleMap = require('./RuleMap');

var RE_IMG_URL = /url\s*\(\s*(['"]?)([^"'\)]*)\1\s*\)/gi;
var RE_URL = /(?:\s*)url\((?:(?:"|')?)(?:\s*)([^\)"']*)(?:\s*)(?:(?:"|')?)\)(?:\s*)/;
var requireJsReg = /\brequire\s*\(\s*(["'])([^'"\s]+)\1\s*\)/g;
var requireAsyncJsReg = /\brequire\s*\.async\(\s*["']([^'"\s]+)["'][^\)]*\)/g;

/**
 * 冻结方法
 * @param {object} obj
 * @param {Array} props
 */
function seal(obj, props) {
  props.forEach(props, function(prop) {
    Object.defineProperty(obj, prop, {
      writable: false,
      enumerable: true,
      value: obj[prop]
    });
  });
}

/**
 * 判断给定路径是否网络绝对路径, 即http(s)://开头的路径
 * @param {string} url
 * @returns {boolean}
 */
function isAbsUrl(url) {
  return /:\//.test(url);
}

/**
 * 给模块代码加入cmd wrapper
 * @param {JSResource} jsResource
 * @param {object} options
 */
function cmdWrapper(jsResource, options) {
  /*
   jsResource.getContent().replace(/\/\*([\s\S]*?)\*\//m, function(match) {
   console.log(match);
   return match + '\n\n' + 'define(){';
   }) + '})';
   */
  var content =
      options.commentdoc + '\n' +
      options.define + '("' + jsResource.id + '", function(require, exports, module) {\n' +
      (options.usestrict ? '"use strict";' : '') +
      jsResource.getContent() + '\n});';

  jsResource.setContent(content);
}

/**
 * Task
 * @param {string}      name
 * @param {?object}     options
 * @param {?object}     soiOptions
 * @param {?object}     args
 * @param {ResourceMap} map
 * @constructor
 */
function Task(name, options, soiOptions, args, map) {
  this.name = name;
  this.rules = new RuleMap();
  this.plugins = new PluginMap();
  this.options = options;
  this.args = args; //命令行相关参数
  this.soiOptions = soiOptions;
  this.map = map;

  seal(this, [
    'addRule', 'use', 'run', 'setArgs', 'setMap', '_apply', 'config', '_mergeRule',
    'beforeCompile', 'compile', '_compileImage', '_compileCSS', '_compileJS',
    'pack', 'postProcess', 'shim', 'flush'
  ]);
}

inherits(Task, EventEmitter);

/**
 * 合并soi共用规则和当前task的规则
 */
Task.prototype._mergeRule = function() {
  this.rules.merge(soi.rules);
};

/**
 * 编译图片资源
 * @param {ImageResource} resource
 */
Task.prototype._compileImage = function(resource) {
  // 暂时不需要做什么额外的操作
  this.emit('compiled', resource);
  this.resolveProductUriInternal(resource);
  resource.isCompiled = true;
};

/**
 * 编译css资源
 * @param {CssResource} resource
 */
Task.prototype._compileCSS = function(resource) {
  var task = this;
  // 替换css中的资源, 递归编译
  resource.getContent()
      .replace(RE_URL, function($0, $1) {
        if (isAbsUrl($1)) {
          return $1;
        }

        var uri = path.resolve(resource.path, $1);
        var inlineResource = map.getResourceByPath(uri);
        // 若图片未编译
        if (inlineResource && !inlineResource.isCompiled) {
          task._compileImage(inlineResource);
          return inlineResource.uri;
        }
        // todo warning
        return $1;
      });

  this.emit('compiled', resource);
  this.resolveProductUriInternal(resource);
  resource.isCompiled = true;
};

/**
 * 编译js资源
 * @param {JSResource} resource
 */
Task.prototype._compileJS = function(resource) {
  var task = this;

  resource.getContent()
      .replace(requireJsReg, function(match, $1, $2) {
        // $2 就是匹配出来的依赖路径
        var dirName = path.parse(resource.path).dir, url;
        match = match.replace(/\s/g, '');
        url =  soi.util.normalizeSysPath(path.resolve(dirName, $2));
        var inlineResource = task.map.resourcePathMap[url];
        if (inlineResource && !inlineResource.isCompiled) {
          task._compileJS(inlineResource);
        }

        return match.replace($2, inlineResource.id);
      })
      .replace(requireAsycJsReg, function(match, dep) {
        // todo dep 是依赖数组
        var dirName = path.parse(resource.path).dir, url;
        match = match.replace(/\s/g, '');
        url =  soi.util.normalizeSysPath(path.resolve(dirName, dep));
        var inlineResource = task.map.resourcePathMap[url];
        if (inlineResource && !inlineResource.isCompiled) {
          task._compileJS(inlineResource);
        }

        return match.replace(dep, inlineResource.id);
      });

  if (resource.isModule) {
    cmdWrapper(resource, task.config.get('cmdWrapper'));
  }

  this.emit('compiled', resource);
  this.resolveProductUriInternal(resource);
  resource.isCompiled = true;
};

/**
 * 应用插件
 */
Task.prototype._apply = function() {
  this.plugins._apply(this);
  return this;
};


//===============================================
// 以下为公共API, 不可改变
//===============================================
/**
 * 设置命令行相关参数
 * @param {object} params
 * @returns {Task}
 */
Task.prototype.setArgs = function (params) {
  this.args = params;
  return this;
};

/**
 * 设置map资源表相关
 * @param {ResourceMap} map
 * @returns {Task}
 */
Task.prototype.setMap = function (map) {
  this.map = map;
  return this;
};

/**
 * 添加规则
 * @param {string|RegExp} pattern
 * @param {?object} options
 */
Task.prototype.addRule = function(pattern, options) {
  this.rules.add(pattern, options);
  return this;
};

/**
 * 记录要使用的服务插件
 * @param {string} plug
 * @param {?object} options
 * @return {Task}
 */
Task.prototype.use = function (plug, options) {
  this.plugins.add(plug, options);
  return this;
};

/**
 * 执行
 */
Task.prototype.run = function() {
  this._mergeRule();
  this._apply();
  this.emit('beforeCompile', this);
  this.beforeCompile(function() {
    this.emit('compile', this);
    // 编译
    this.compile(function() {
      this.emit('compileEnd', this);
      this.emit('pack', this);
      // 合并打包
      this.pack(function() {
{'fraction_non_alphanumeric': 0.20356103406950865, 'fraction_numerical': 0.0022256462934429036, 'mean_word_length': 3.1561721807186056, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '2788929', 'n_tokens_mistral': 4172, 'n_tokens_neox': 4280, 'n_words': 738}