<commit_before>var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var debug = require('debug')('theme:finder');

exports.pkg = pkg;
exports.shadow = shadow;
exports.shadows = shadows;

/**
*
* Create a shadow link of theme's static folder.
* 
* @param {[Theme Object]} [theme] the theme object.
* @param {[String]} [realPath] [the realPath of target theme]
* @param {[Function]} [callback] [the callback function]
*
**/
function shadow(theme, public, callback) {
  if (!theme) 
    return false;
  if (!theme.realPath) 
    return false;
  if (!public) 
    return false;

  var cb = isFunction(callback) ? callback : function() {};

  if (isRemote(theme.static)) 
    return cb(null);

  var statics = path.join(theme.realPath, theme.static || './static');
  var shadow = path.join(public, theme.name);

  try {
    if (!fs.existsSync(public)) 
      fs.mkdirSync(public);
  } catch (err) {
    throw err;
  }

  try {
    if (fs.readlinkSync(shadow) === statics)
      return cb(null);
  } catch (err) {
    fs.symlinkSync(statics, shadow, 'dir'); // if link do not exist
    return cb(null);
  }

  try {
    // 如果软链没有指向目标，删除软链
    fs.unlinkSync(shadow);
    // 重新生成软链
    fs.symlinkSync(statics, shadow, 'dir');
    return cb(null);
  } catch (err) {
    throw err;
  }
}

/**
*
* Create shadows of a theme instance.
* @param {[Theme Object]} [self]
*
**/
function shadows(self) {
  var defaultStaticDir = './static';
  var dir = path.join(self.home, './node_modules');

  if (!fs.existsSync(dir)) 
    return null;

  var files = fs.readdirSync(dir);

  if (!files || files.length === 0) 
    return null;

  var modules = files.filter(function(folder) {
    var abs = path.join(dir, folder);
    var isDir = fs.statSync(abs).isDirectory();
    if (!isDir) 
      return false;
    // [此处有硬编码] 如果不是主题文件夹，直接跳过
    if (folder.indexOf('-theme-') === -1) 
      return false;
    // 如果已经存在 shadow，直接跳过
    if (fs.existsSync(path.join(self.publics, folder))) 
      return true;
    // 如果没有默认的 static folder，直接跳过
    if (!fs.existsSync(path.join(abs, defaultStaticDir))) 
      return false;

    var theme = {}
    theme.name = folder;
    theme.realPath = abs;
    theme.static = defaultStaticDir;
    exports.shadow(theme, self.publics);
    
    return true;
  });

  return modules;
}

// Fetch package.json from parent dir
function pkg(home) {
  try {
    return require(path.join(home, './package.json'));
  } catch (err) {
    return {};
  }
}

// Check if a string is uri
function isRemote(dir) {
  return dir && (dir.indexOf('http') === 0 || dir.indexOf('https') === 0);
}

// Check if a `fn` is function
function isFunction(fn) {
  return fn && _.isFunction(fn);<commit_msg>0.1: Bugfix, Add more comments<commit_after>var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var debug = require('debug')('theme:finder');

exports.pkg = pkg;
exports.shadow = shadow;
exports.shadows = shadows;

/**
*
* Create a shadow link of theme's static folder.
* 
* @param {[Theme Object]} [theme] the theme object.
* @param {[String]} [realPath] [the realPath of target theme]
* @param {[Function]} [callback] [the callback function]
*
**/
function shadow(theme, public, callback) {
  if (!theme) 
    return false;
  if (!theme.realPath) 
    return false;
  if (!public) 
    return false;

  var cb = isFunction(callback) ? callback : function() {};

  // Ignore URIs.
  if (isRemote(theme.static)) 
    return cb(null);

  var statics = path.join(theme.realPath, theme.static || './static');
  var shadow = path.join(public, theme.name);

  // Check if public folder exist,
  // If not, create a blank public folder using given
  try {
    if (!fs.existsSync(public)) 
      fs.mkdirSync(public);
  } catch (err) {
    throw err;
  }

  // Check if a shadow is linked to real static folder
  try {
    if (fs.readlinkSync(shadow) === statics)
      return cb(null);
  } catch (err) {
    // If link do not exist,
    // Create a shadow link.
    fs.symlinkSync(statics, shadow, 'dir');
    return cb(null);
  }

  // If a shadow is not linked to the given static folder path
  // Remove it first
  try {
    fs.unlinkSync(shadow);
    fs.symlinkSync(statics, shadow, 'dir');
    return cb(null);
  } catch (err) {
    throw err;
  }
}

/**
*
* Create static folders' shadows of a theme instance.
* @param {[Theme Object]} [self]
*
**/
function shadows(self) {
  var node_modules = path.join(self.path.home, './node_modules');

  if (!fs.existsSync(node_modules)) 
    return null;

  var files = fs.readdirSync(node_modules);

  if (!files || files.length === 0) 
    return null;

  var modules = files.filter(function(folder) {
    var modulePath = path.join(node_modules, folder);
    var isDir = fs.statSync(modulePath).isDirectory();
    var packagePath = path.join(modulePath, './package.json');

    // Check if it's a valid folder
    if (!isDir) return;

    // Check if the folder is a theme module
    if (folder.indexOf(self.pattern) === -1) return;

    // Check if there is a exist shadow
    if (fs.existsSync(path.join(self.path.public, folder))) return;

    if (fs.existsSync(packagePath)) {
      try {
        var packageJSON = fs.readJSON(packagePath);
      } catch (err) {
        var packageJSON = {};
      }
    }

    // The relative static folder path of this theme module.
    var staticPath = packageJSON.static || './static';

    // Check if there is a valid static folder in this theme module
    if (!fs.existsSync(path.join(modulePath, staticPath))) return;

    var theme = {};
    theme.name = folder;
    theme.realPath = modulePath;
    theme.static = staticPath;

    shadow(theme, self.path.public);
    
    return true;
  });

  return modules;
}

// Fetch package.json from parent dir
function pkg(home) {
  try {
    return require(path.join(home, './package.json'));
  } catch (err) {
    return {};
  }
}

// Check if a string is uri
function isRemote(dir) {
  return dir && (dir.indexOf('http') === 0 || dir.indexOf('https') === 0);
}

// Check if a `fn` is function
function isFunction(fn) {
  return fn && _.isFunction(fn);
{'fraction_non_alphanumeric': 0.15207823960880196, 'fraction_numerical': 0.0016299918500407497, 'mean_word_length': 3.023606557377049, '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': '2301771', 'n_tokens_mistral': 2080, 'n_tokens_neox': 2030, 'n_words': 574}