<commit_before>/*jshint globalstrict:true, devel:true */
/*eslint no-var:0 */
/*global require, module, Buffer */
"use strict";

var path  = require('path'),
    zip   = require('jszip'),
    etree = require('elementtree');

module.exports = (function() {

    var DOCUMENT_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
        CALC_CHAIN_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain",
        SHARED_STRINGS_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";

    /**
     * Create a new workbook. Either pass the raw data of a .xlsx file,
     * or call `loadTemplate()` later.
     */
    var Workbook = function(data) {
        var self = this;

        self.archive = null;
        self.sharedStrings = [];
        self.sharedStringsLookup = {};

        if(data) {
            self.loadTemplate(data);
        }
    };

    var _get_simple = function (obj, desc) {
        if (desc.indexOf("[") >=0 ) {
            var specification = desc.split(/[[[\]]/);
            var property = specification[0];
            var index = specification[1];
            return obj[property][index];
        }
        
        return obj[desc];
    }

    /**
     * Based on http://stackoverflow.com/questions/8051975
     * Mimic https://lodash.com/docs#get
     */
    var _get = function(obj, desc, defaultValue) {
        var arr = desc.split('.');
        try {
            while (arr.length) {
                obj = _get_simple(obj, arr.shift());
            }
        } catch(ex) {
            /* invalid chain */
            obj = undefined;
        }
        return obj === undefined ? defaultValue : obj;
    }

    /**
    * Delete unused sheets if needed
    */
    Workbook.prototype.deleteSheet = function(sheetName){
      var self = this;
      var sheet = self.loadSheet(sheetName);

      var sh = self.workbook.find("sheets/sheet[@sheetId='" + sheet.id + "']");
      self.workbook.find("sheets").remove(sh);
			
      var rel = self.workbookRels.find("Relationship[@Id='" + sh.attrib['r:id'] + "']");
      self.workbookRels.remove(rel);

      self._rebuild();
      return self
    };

    /**
    * Clone sheets in current workbook template
    */
    Workbook.prototype.copySheet = function(sheetName, copyName){
      var self = this;
      var sheet = self.loadSheet(sheetName); //filename, name , id, root
      var newSheetIndex = (self.workbook.findall("sheets/sheet").length+1).toString();
      var fileName = 'worksheets' + '/' + 'sheet' + newSheetIndex + '.xml';
      var arcName = self.prefix + '/' + fileName;

      self.archive.file(arcName, etree.tostring(sheet.root) );			
      self.archive.files[arcName].options.binary = true;

      var newSheet = etree.SubElement( self.workbook.find('sheets'), 'sheet' );
      newSheet.attrib.name = copyName || 'Sheet' + newSheetIndex;
      newSheet.attrib.sheetId = newSheetIndex; 
      newSheet.attrib['r:id'] = 'rId' + newSheetIndex;

      var newRel = etree.SubElement(self.workbookRels, 'Relationship');
      newRel.attrib.Type = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet';
      newRel.attrib.Target = fileName;

      self._rebuild();
//    TODO: work with "definedNames" 
//    var defn = etree.SubElement(self.workbook.find('definedNames'), 'definedName');
//
      return self
    };


    /**
    *  Partially rebuild after copy/delete sheets
    */
    Workbook.prototype._rebuild = function(){
    //each <sheet> 'r:id' attribute in '\xl\workbook.xml'
    //must point to correct <Relationship> 'Id' in xl\_rels\workbook.xml.rels
      var self = this;
      var order = ['worksheet', 'theme', 'styles','sharedStrings']; 
        
      self.workbookRels.findall("*")
      .sort(function(rel1, rel2){ //using order
        var index1 = order.indexOf( path.basename(rel1.attrib.Type) ); 
        var index2 = order.indexOf( path.basename(rel2.attrib.Type) ); 
        if ((index1 + index2) == 0) 
          return rel1._id - rel2._id;
        return index1 - index2
      })
      .forEach(function(item, index) {
        item.attrib.Id = 'rId' + (index+1);
      })
        
      self.workbook.findall("sheets/sheet").forEach(function(item, index) {
        item.attrib['r:id'] = 'rId' + (index+1);
        item.attrib.sheetId = (index+1).toString();
      })
        
      self.archive.file(self.prefix + '/' + '_rels' + '/' + path.basename(self.workbookPath) + '.rels', etree.tostring(self.workbookRels));
      self.archive.file(self.workbookPath, etree.tostring(self.workbook));
      self.sheets = self.loadSheets(self.prefix, self.workbook, self.workbookRels);
    }


    /**
     * Load a .xlsx file from a byte array.
     */<commit_msg>workbookRels _id sort could be diff with attrib.Id sort. It is possible get wrong sheet when load, delete, copy sheet. So when attrib.Id has value, use it sort. otherwise use _id sort<commit_after>/*jshint globalstrict:true, devel:true */
/*eslint no-var:0 */
/*global require, module, Buffer */
"use strict";

var path  = require('path'),
    zip   = require('jszip'),
    etree = require('elementtree');

module.exports = (function() {

    var DOCUMENT_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
        CALC_CHAIN_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain",
        SHARED_STRINGS_RELATIONSHIP = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";

    /**
     * Create a new workbook. Either pass the raw data of a .xlsx file,
     * or call `loadTemplate()` later.
     */
    var Workbook = function(data) {
        var self = this;

        self.archive = null;
        self.sharedStrings = [];
        self.sharedStringsLookup = {};

        if(data) {
            self.loadTemplate(data);
        }
    };

    var _get_simple = function (obj, desc) {
        if (desc.indexOf("[") >=0 ) {
            var specification = desc.split(/[[[\]]/);
            var property = specification[0];
            var index = specification[1];
            return obj[property][index];
        }
        
        return obj[desc];
    }

    /**
     * Based on http://stackoverflow.com/questions/8051975
     * Mimic https://lodash.com/docs#get
     */
    var _get = function(obj, desc, defaultValue) {
        var arr = desc.split('.');
        try {
            while (arr.length) {
                obj = _get_simple(obj, arr.shift());
            }
        } catch(ex) {
            /* invalid chain */
            obj = undefined;
        }
        return obj === undefined ? defaultValue : obj;
    }

    /**
    * Delete unused sheets if needed
    */
    Workbook.prototype.deleteSheet = function(sheetName){
      var self = this;
      var sheet = self.loadSheet(sheetName);

      var sh = self.workbook.find("sheets/sheet[@sheetId='" + sheet.id + "']");
      self.workbook.find("sheets").remove(sh);
			
      var rel = self.workbookRels.find("Relationship[@Id='" + sh.attrib['r:id'] + "']");
      self.workbookRels.remove(rel);

      self._rebuild();
      return self
    };

    /**
    * Clone sheets in current workbook template
    */
    Workbook.prototype.copySheet = function(sheetName, copyName){
      var self = this;
      var sheet = self.loadSheet(sheetName); //filename, name , id, root
      var newSheetIndex = (self.workbook.findall("sheets/sheet").length+1).toString();
      var fileName = 'worksheets' + '/' + 'sheet' + newSheetIndex + '.xml';
      var arcName = self.prefix + '/' + fileName;

      self.archive.file(arcName, etree.tostring(sheet.root) );			
      self.archive.files[arcName].options.binary = true;

      var newSheet = etree.SubElement( self.workbook.find('sheets'), 'sheet' );
      newSheet.attrib.name = copyName || 'Sheet' + newSheetIndex;
      newSheet.attrib.sheetId = newSheetIndex; 
      newSheet.attrib['r:id'] = 'rId' + newSheetIndex;

      var newRel = etree.SubElement(self.workbookRels, 'Relationship');
      newRel.attrib.Type = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet';
      newRel.attrib.Target = fileName;

      self._rebuild();
//    TODO: work with "definedNames" 
//    var defn = etree.SubElement(self.workbook.find('definedNames'), 'definedName');
//
      return self
    };


    /**
    *  Partially rebuild after copy/delete sheets
    */
    Workbook.prototype._rebuild = function(){
    //each <sheet> 'r:id' attribute in '\xl\workbook.xml'
    //must point to correct <Relationship> 'Id' in xl\_rels\workbook.xml.rels
      var self = this;
      var order = ['worksheet', 'theme', 'styles','sharedStrings']; 
        
      self.workbookRels.findall("*")
      .sort(function(rel1, rel2){ //using order
        var index1 = order.indexOf( path.basename(rel1.attrib.Type) ); 
        var index2 = order.indexOf( path.basename(rel2.attrib.Type) ); 
        if ((index1 + index2) == 0) {
            if(rel1.attrib.Id && rel2.attrib.Id) return rel1.attrib.Id.substring(3) - rel2.attrib.Id.substring(3);
          return rel1._id - rel2._id;
        }
        return index1 - index2
      })
      .forEach(function(item, index) {
        item.attrib.Id = 'rId' + (index+1);
      })
        
      self.workbook.findall("sheets/sheet").forEach(function(item, index) {
        item.attrib['r:id'] = 'rId' + (index+1);
        item.attrib.sheetId = (index+1).toString();
      })
        
      self.archive.file(self.prefix + '/' + '_rels' + '/' + path.basename(self.workbookPath) + '.rels', etree.tostring(self.workbookRels));
      self.archive.file(self.workbookPath, etree.tostring(self.workbook));
      self.sheets = self.loadSheets(self.prefix, self.workbook, self.workbookRels);
    }


    /**
     * Load a .xlsx file from a byte array.
     */
{'fraction_non_alphanumeric': 0.14888487040385776, 'fraction_numerical': 0.009443439823186659, 'mean_word_length': 2.461404728789986, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 14}, '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': '1488156', 'n_tokens_mistral': 3248, 'n_tokens_neox': 3112, 'n_words': 604}