<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The extract_tarball implementation is based heavily on code from NPM:
 *
 *   <http://github.com/isaacs/npm/blob/master/lib/utils/exec.js>
 *
 * Copyright 2009, 2010 Isaac Zimmitti Schlueter. All rights reserved.
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

var fs = require('fs');
var sys = require('sys');
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var path = require('path');

var sprintf = require('extern/sprintf').sprintf;
var async = require('extern/async');

var log = require('util/log');
var config = require('util/config');
var fsutil = require('util/fs');
var misc = require('util/misc');

exports.extract_tarball = function(tarball, target, mode, cb) {
  fs.mkdir(target, mode, function(err) {
    if (err) {
      return cb(err);
    }

    var completed = false;

    function on_error(err) {
      completed = true;
      fsutil.rmtree(target, function() {
        return cb(err);
      });
    }

    var gzip = spawn(config.get().gzip, ['--decompress', '--stdout', '-f', tarball]);
    var tar = spawn(config.get().tar, ['vx', '--strip-components=1', '-C', target]);

    gzip.on('exit', function(code) {
      if (code && !completed) {
        log.err("Error decompressing bundle, gzip exited with code: " + code);
        try {
          tar.kill();
        }
        catch (err) {
          log.warn("Unable to kill tar: " + err);
        }
        return on_error(new Error("Error decompressing bundle"));
      }
    });

    tar.on('exit', function(code) {
      if (!completed) {
        if (code) {
          return on_error(new Error("Error extracting tarball"));
        }
        else {
          completed = true;
          cb();
        }
      }
    });

    sys.pump(gzip.stdout, tar.stdin);
  });
};

/**
 * Create a tarball from the specified path.
 *
 * @param {String} source_path Path to the directory or the file you want to archive
 * @param {String} destination_path Path to the directory where the tarball will be saved
 * @param {String} tarball_name The name of the tarball
 * @param {Object} options Options object
 * @param {Function) callback A callback called with a possible error
 *
 */
exports.create_tarball = function(source_path, target_path, tarball_name, options, callback) {
  var default_options = {
    'delete_if_exists': false,
    'ignore_file_changed_error': false,
    'exclude_pattern': '',
    'store_in_tarball_name_directory': true // If true, all the files inside the archive will be stored in a
                                            // directory named tarball_name minus the .tar.gz extension
  };

  var options = misc.merge(default_options, options);
  var options_array = [];

  var tarball_path = path.join(target_path, tarball_name);

  async.parallel([function(callback) {
      path.exists(source_path, function(exists) {
        if (!exists) {
          return callback(new Error('Source path does not exist'));
        }

        callback();
      });
    },

    function(callback) {
       path.exists(target_path, function(exists) {
        if (!exists) {
          return callback(new Error('Target path does not exist'));
        }

        callback();
      });
    },

    function(callback) {
      path.exists(tarball_path, function(exists) {
        if (exists) {
          if (!options.delete_if_exists) {
            return callback(new Error(sprintf('Tarball already exists: %s', tarball_path)));
          }

          fs.unlink(tarball_path, function(error) {
            if (error) {
              return callback(error);
            }

            callback();
          });
        }

        callback();
      });
    }],

    function(error, results) {
      if (error) {
        return callback(error);
      }

      var base_name = tarball_name.replace('.tar.gz', '');

      function handle_error(error) {
        fs.unlink(tarball_path, function() {
          return callback(error);
        });
      }

      if (options.exclude_pattern) {
        options_array.push(sprintf('--exclude %s', options.exclude_pattern));
      }

      if (options.store_in_tarball_name_directory) {
        options_array.push(sprintf('--transform \'s,^./*,%s/,\'', base_name));
      }

      var tarcmd = sprintf('%s czpf "%s" -C "%s" --exclude=%s %s .', config.get().tar, tarball_path, source_path, base_name, options_array.join(' '));
      var tar = exec(tarcmd, {}, function(error, stdout, stderr) {
        if (error && !(options.ignore_file_changed_error && error.code === 1 && stderr.match(/file changed as we read it/i))) {
          log.err(sprintf('Creating tarball failed: (%s) %s', error.code, stderr));
          return handle_error(new Error(sprintf('Creating tarball failed: %s', stderr)));
        }

        log.info(sprintf('Successfully created tarball: %s', tarball_name));
        callback();
      });
    }
  );
};

/**
 * Return an array of files and directories in a tarball.
 *
 * @param {String} tarball_path Path to the tarball
 * @param {Function) callback A callback called with a possible error as the first argument and an array
 *                            with all the files and directories in an archive as the second argument on success.
 *
 */
exports.get_tarball_file_list = function(tarball_path, callback) {
  var file_list = [];

  var tarcmd = sprintf('%s tvf "%s"', config.get().tar, tarball_path);
  var tar = exec(tarcmd, function(error, stdout, stderr) {
    var line, match;

    if (error) {
      return callback(error, null);
    }

    var lines = stdout.split(/\n\r?/g);

    for (var i = 0; i < lines.length; i++) {
      line = lines[i];
      match = line.match(/^.*\s(.*?)$/);

      if (match) {
        file_list.push(match[1].trim());
      }
    }

    callback(null, file_list);
  });
};
<commit_msg>log tarball command used<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The extract_tarball implementation is based heavily on code from NPM:
 *
 *   <http://github.com/isaacs/npm/blob/master/lib/utils/exec.js>
 *
 * Copyright 2009, 2010 Isaac Zimmitti Schlueter. All rights reserved.
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

var fs = require('fs');
var sys = require('sys');
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var path = require('path');

var sprintf = require('extern/sprintf').sprintf;
var async = require('extern/async');

var log = require('util/log');
var config = require('util/config');
var fsutil = require('util/fs');
var misc = require('util/misc');

exports.extract_tarball = function(tarball, target, mode, cb) {
  fs.mkdir(target, mode, function(err) {
    if (err) {
      return cb(err);
    }

    var completed = false;

    function on_error(err) {
      completed = true;
      fsutil.rmtree(target, function() {
        return cb(err);
      });
    }

    var gzip = spawn(config.get().gzip, ['--decompress', '--stdout', '-f', tarball]);
    var tar = spawn(config.get().tar, ['vx', '--strip-components=1', '-C', target]);

    gzip.on('exit', function(code) {
      if (code && !completed) {
        log.err("Error decompressing bundle, gzip exited with code: " + code);
        try {
          tar.kill();
        }
        catch (err) {
          log.warn("Unable to kill tar: " + err);
        }
        return on_error(new Error("Error decompressing bundle"));
      }
    });

    tar.on('exit', function(code) {
      if (!completed) {
        if (code) {
          return on_error(new Error("Error extracting tarball"));
        }
        else {
          completed = true;
          cb();
        }
      }
    });

    sys.pump(gzip.stdout, tar.stdin);
  });
};

/**
 * Create a tarball from the specified path.
 *
 * @param {String} source_path Path to the directory or the file you want to archive
 * @param {String} destination_path Path to the directory where the tarball will be saved
 * @param {String} tarball_name The name of the tarball
 * @param {Object} options Options object
 * @param {Function) callback A callback called with a possible error
 *
 */
exports.create_tarball = function(source_path, target_path, tarball_name, options, callback) {
  var default_options = {
    'delete_if_exists': false,
    'ignore_file_changed_error': false,
    'exclude_pattern': '',
    'store_in_tarball_name_directory': true // If true, all the files inside the archive will be stored in a
                                            // directory named tarball_name minus the .tar.gz extension
  };

  var options = misc.merge(default_options, options);
  var options_array = [];

  var tarball_path = path.join(target_path, tarball_name);

  async.parallel([function(callback) {
      path.exists(source_path, function(exists) {
        if (!exists) {
          return callback(new Error('Source path does not exist'));
        }

        callback();
      });
    },

    function(callback) {
       path.exists(target_path, function(exists) {
        if (!exists) {
          return callback(new Error('Target path does not exist'));
        }

        callback();
      });
    },

    function(callback) {
      path.exists(tarball_path, function(exists) {
        if (exists) {
          if (!options.delete_if_exists) {
            return callback(new Error(sprintf('Tarball already exists: %s', tarball_path)));
          }

          fs.unlink(tarball_path, function(error) {
            if (error) {
              return callback(error);
            }

            callback();
          });
        }

        callback();
      });
    }],

    function(error, results) {
      if (error) {
        return callback(error);
      }

      var base_name = tarball_name.replace('.tar.gz', '');

      function handle_error(error) {
        fs.unlink(tarball_path, function() {
          return callback(error);
        });
      }

      if (options.exclude_pattern) {
        options_array.push(sprintf('--exclude %s', options.exclude_pattern));
      }

      if (options.store_in_tarball_name_directory) {
        options_array.push(sprintf('--transform \'s,^./*,%s/,\'', base_name));
      }

      var tarcmd = sprintf('%s czpf "%s" -C "%s" --exclude=%s %s .', config.get().tar, tarball_path, source_path, base_name, options_array.join(' '));
      var tar = exec(tarcmd, {}, function(error, stdout, stderr) {
        if (error && !(options.ignore_file_changed_error && error.code === 1 && stderr.match(/file changed as we read it/i))) {
          log.err(sprintf('Creating tarball failed: (%s) %s\nCommand was: %s', error.code, stderr, tarcmd));
          return handle_error(new Error(sprintf('Creating tarball failed: %s', stderr)));
        }

        log.info(sprintf('Successfully created tarball: %s', tarball_name));
        callback();
      });
    }
  );
};

/**
 * Return an array of files and directories in a tarball.
 *
 * @param {String} tarball_path Path to the tarball
 * @param {Function) callback A callback called with a possible error as the first argument and an array
 *                            with all the files and directories in an archive as the second argument on success.
 *
 */
exports.get_tarball_file_list = function(tarball_path, callback) {
  var file_list = [];

  var tarcmd = sprintf('%s tvf "%s"', config.get().tar, tarball_path);
  var tar = exec(tarcmd, function(error, stdout, stderr) {
    var line, match;

    if (error) {
      return callback(error, null);
    }

    var lines = stdout.split(/\n\r?/g);

    for (var i = 0; i < lines.length; i++) {
      line = lines[i];
      match = line.match(/^.*\s(.*?)$/);

      if (match) {
        file_list.push(match[1].trim());
      }
    }

    callback(null, file_list);
  });
};
<|endoftext|>


<commit_before>/**
 * An `extend` util method which transfers source the
 * properties and its respectives values to the destination
 * object. This method does not accept arrays (since we don't need it)
 *
 * @usage
 * var x = { hello: 'world' };
 * var y = extend(x, { hello: 'javascript'});
 * // x == y => true
 *
 * @param {Object} dest
 * @param {...Object} object sources (to copy from)
 * @return {Object}
 */
module.exports = function(dest) {
  // Let's bail when the destionation object is not an object
  _throw(arg, 'Dest');

  for ( var i = 1; i < arguments.length; i++ ) {
    var arg = arguments[i];

    // We'll test each argument to produce proper errors
    // if the provided argument is invalid
    _throw(arg, 'Source object');

    // Iterate through each mudafucka
    for ( key in arg ) {
      dest[key] = arg[key];
    }
  }

  return dest;
}

/**
 * Utility method of a utility method (lol)
 * that just executes `isObject`, and then
 * throws an exception if it returns false
 *
 * @throws Error
 * @param {mixed} argument to be tested
 * @param {string} Label to be printed out to the console
 * @return {void}
 */
function _throw(arg, label) {
  if ( !isObject(arg) ) {
    throw new Error(label + ' you provided (' +
      dest + ') is not a valid object.');
  }
}<commit_msg>Fixed undefined `isObject` variable<commit_after>var isObject = require('./isObject');

/**
 * An `extend` util method which transfers source the
 * properties and its respectives values to the destination
 * object. This method does not accept arrays (since we don't need it)
 *
 * @usage
 * var x = { hello: 'world' };
 * var y = extend(x, { hello: 'javascript'});
 * // x == y => true
 *
 * @param {Object} dest
 * @param {...Object} object sources (to copy from)
 * @return {Object}
 */
module.exports = function(dest) {
  // Let's bail when the destionation object is not an object
  _throw(arg, 'Dest');

  for ( var i = 1; i < arguments.length; i++ ) {
    var arg = arguments[i];

    // We'll test each argument to produce proper errors
    // if the provided argument is invalid
    _throw(arg, 'Source object');

    // Iterate through each mudafucka
    for ( key in arg ) {
      dest[key] = arg[key];
    }
  }

  return dest;
}

/**
 * Utility method of a utility method (lol)
 * that just executes `isObject`, and then
 * throws an exception if it returns false
 *
 * @throws Error
 * @param {mixed} argument to be tested
 * @param {string} Label to be printed out to the console
 * @return {void}
 */
function _throw(arg, label) {
  if ( !isObject(arg) ) {
    throw new Error(label + ' you provided (' +
      dest + ') is not a valid object.');
  }
}<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The extractTarball implementation is based heavily on code from NPM:
 *
 *   <http://github.com/isaacs/npm/blob/master/lib/utils/exec.js>
 *
 * Copyright 2009, 2010 Isaac Zimmitti Schlueter. All rights reserved.
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

var fs = require('fs');
var sys = require('sys');
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var path = require('path');

var sprintf = require('sprintf').sprintf;
var async = require('async');

var log = require('util/log');
var config = require('util/config');
var fsutil = require('util/fs');
var misc = require('util/misc');
var norris = require('norris');

exports.extractTarball = function(tarball, target, mode, cb) {
  fs.mkdir(target, mode, function(err) {
    if (err) {
      return cb(err);
    }

    var completed = false;

    function onError(err) {
      completed = true;
      fsutil.rmtree(target, function() {
        return cb(err);
      });
    }

    norris.get(function(facts) {
      var gzip = spawn(config.get()['gzip'], ['--decompress', '--stdout', '-f', tarball]);
      var tar = spawn(facts.gnutar, ['vx', '--file=-', '--strip-components=1', '-C', target]);

      gzip.on('exit', function(code) {
        if (code && !completed) {
          log.err('Error decompressing bundle, gzip exited with code: ' + code);
          try {
            tar.kill();
          }
          catch (err) {
            log.warn('Unable to kill tar: ' + err);
          }
          return onError(new Error('Error decompressing bundle'));
        }
      });

      tar.on('exit', function(code) {
        if (!completed) {
          if (code) {
            return onError(new Error('Error extracting tarball. tar exited with code: ' + code));
          }
          else {
            completed = true;
            cb();
          }
        }
      });

      sys.pump(gzip.stdout, tar.stdin);
    });
  });
};

/**
 * Create a tarball from the specified path.
 *
 * @param {String} sourcePath Path to the directory or the file you want to archive.
 * @param {String} destinationPath Path to the directory where the tarball will be saved.
 * @param {String} tarballName The name of the tarball.
 * @param {Object} options Options object.
 * @param {Function} callback A callback called with a possible error.
 *
 */
exports.createTarball = function(sourcePath, targetPath, tarballName, options, callback) {
  var defaultOptions = {
    deleteIfExists: false,
    ignoreFileChangedError: false,
    excludePattern: '',
    excludeFile: null,
    storeInTarballNameDirectory: true // If true, all the files inside the archive will be stored in a
                                            // directory named tarball_name minus the .tar.gz extension
  };

  options = misc.merge(defaultOptions, options);
  var optionsArray = [];

  var tarballPath = path.join(targetPath, tarballName);

  async.parallel([function(callback) {
      path.exists(sourcePath, function(exists) {
        if (!exists) {
          callback(new Error('Source path does not exist'));
          return;
        }

        callback();
      });
    },

    function(callback) {
       path.exists(targetPath, function(exists) {
        if (!exists) {
          callback(new Error('Target path does not exist'));
          return;
        }

        callback();
      });
    },

    function(callback) {
      path.exists(tarballPath, function(exists) {
        if (exists) {
          if (!options.deleteIfExists) {
            callback(new Error(sprintf('Tarball already exists: %s', tarballPath)));
            return;
          }

          fs.unlink(tarballPath, function(err) {
            if (err) {
              callback(err);
              return;
            }

            callback();
          });
        }

        callback();
      });
    }],

    function(err, results) {
      if (err) {
        callback(err);
        return;
      }

      var baseName = tarballName.replace('.tar.gz', '');

      function handleError(err) {
        fs.unlink(tarballPath, function() {
          callback(err);
          return;
        });
      }

      if (options.excludePattern) {
        optionsArray.push(sprintf('--exclude=%s', options.excludePattern));
      }

      if (options.excludeFile) {
        optionsArray.push(sprintf('--exclude-from=%s', options.excludeFile));
      }

      if (options.storeInTarballNameDirectory) {
        optionsArray.push(sprintf('--transform \'s,^./*,%s/,\'', baseName));
      }

      norris.get(function(facts) {
        var tarcmd = sprintf('%s czpf "%s" -C "%s" --exclude=%s %s .',
                             facts.gnutar, tarballPath, sourcePath, baseName,
                             optionsArray.join(' '));
        var tar = exec(tarcmd, {}, function(err, stdout, stderr) {
          if (err && !(options.ignoreFileChangedError && err.code === 1 && stderr.match(/file changed as we read it/i))) {
            log.err(sprintf('Creating tarball failed: (%s) %s\nCommand was: %s', err.code, stderr, tarcmd));
            return handleError(new Error(sprintf('Creating tarball failed: %s', stderr)));
          }

          log.info(sprintf('Successfully created tarball: %s', tarballName));
          setTimeout(callback, 100);
        });
      });
    }
  );
};

/**
 * Return an array of files and directories in a tarball.
 *
 * @param {String} tarballPath Path to the tarball.
 * @param {Function} callback A callback called with a possible error as the first argument and an array
 *                            with all the files and directories in an archive as the second argument on success.
 *
 */
exports.getTarballFileList = function(tarballPath, callback) {
  var fileList = [];

  norris.get(function(facts) {
    var tarcmd = sprintf('%s tvf "%s"', facts.gnutar, tarballPath);
    var tar = exec(tarcmd, function(err, stdout, stderr) {
      var line, match;

      if (err) {
        callback(err, null);
        return;
      }

      var lines = stdout.split(/\n\r?/g);

      for (var i = 0; i < lines.length; i++) {
        line = lines[i];
        match = line.match(/^.*\s(.*?)$/);

        if (match) {
          fileList.push(match[1].trim());
        }
      }

      callback(null, fileList);
    });
  });
};
<commit_msg>Fix a bug - don't transform symlink names when creating an archive.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The extractTarball implementation is based heavily on code from NPM:
 *
 *   <http://github.com/isaacs/npm/blob/master/lib/utils/exec.js>
 *
 * Copyright 2009, 2010 Isaac Zimmitti Schlueter. All rights reserved.
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

var fs = require('fs');
var sys = require('sys');
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var path = require('path');

var sprintf = require('sprintf').sprintf;
var async = require('async');

var log = require('util/log');
var config = require('util/config');
var fsutil = require('util/fs');
var misc = require('util/misc');
var norris = require('norris');

exports.extractTarball = function(tarball, target, mode, cb) {
  fs.mkdir(target, mode, function(err) {
    if (err) {
      return cb(err);
    }

    var completed = false;

    function onError(err) {
      completed = true;
      fsutil.rmtree(target, function() {
        return cb(err);
      });
    }

    norris.get(function(facts) {
      var gzip = spawn(config.get()['gzip'], ['--decompress', '--stdout', '-f', tarball]);
      var tar = spawn(facts.gnutar, ['vx', '--file=-', '--strip-components=1', '-C', target]);

      gzip.on('exit', function(code) {
        if (code && !completed) {
          log.err('Error decompressing bundle, gzip exited with code: ' + code);
          try {
            tar.kill();
          }
          catch (err) {
            log.warn('Unable to kill tar: ' + err);
          }
          return onError(new Error('Error decompressing bundle'));
        }
      });

      tar.on('exit', function(code) {
        if (!completed) {
          if (code) {
            return onError(new Error('Error extracting tarball. tar exited with code: ' + code));
          }
          else {
            completed = true;
            cb();
          }
        }
      });

      sys.pump(gzip.stdout, tar.stdin);
    });
  });
};

/**
 * Create a tarball from the specified path.
 *
 * @param {String} sourcePath Path to the directory or the file you want to archive.
 * @param {String} destinationPath Path to the directory where the tarball will be saved.
 * @param {String} tarballName The name of the tarball.
 * @param {Object} options Options object.
 * @param {Function} callback A callback called with a possible error.
 *
 */
exports.createTarball = function(sourcePath, targetPath, tarballName, options, callback) {
  var defaultOptions = {
    deleteIfExists: false,
    ignoreFileChangedError: false,
    excludePattern: '',
    excludeFile: null,
    storeInTarballNameDirectory: true // If true, all the files inside the archive will be stored in a
                                            // directory named tarball_name minus the .tar.gz extension
  };

  options = misc.merge(defaultOptions, options);
  var optionsArray = [];

  var tarballPath = path.join(targetPath, tarballName);

  async.parallel([function(callback) {
      path.exists(sourcePath, function(exists) {
        if (!exists) {
          callback(new Error('Source path does not exist'));
          return;
        }

        callback();
      });
    },

    function(callback) {
       path.exists(targetPath, function(exists) {
        if (!exists) {
          callback(new Error('Target path does not exist'));
          return;
        }

        callback();
      });
    },

    function(callback) {
      path.exists(tarballPath, function(exists) {
        if (exists) {
          if (!options.deleteIfExists) {
            callback(new Error(sprintf('Tarball already exists: %s', tarballPath)));
            return;
          }

          fs.unlink(tarballPath, function(err) {
            if (err) {
              callback(err);
              return;
            }

            callback();
          });
        }

        callback();
      });
    }],

    function(err, results) {
      if (err) {
        callback(err);
        return;
      }

      var baseName = tarballName.replace('.tar.gz', '');

      function handleError(err) {
        fs.unlink(tarballPath, function() {
          callback(err);
          return;
        });
      }

      if (options.excludePattern) {
        optionsArray.push(sprintf('--exclude=%s', options.excludePattern));
      }

      if (options.excludeFile) {
        optionsArray.push(sprintf('--exclude-from=%s', options.excludeFile));
      }

      if (options.storeInTarballNameDirectory) {
        optionsArray.push(sprintf('--transform \'s,^./*,%s/,S\'', baseName));
      }

      norris.get(function(facts) {
        var tarcmd = sprintf('%s czpf "%s" -C "%s" --exclude=%s %s .',
                             facts.gnutar, tarballPath, sourcePath, baseName,
                             optionsArray.join(' '));
        var tar = exec(tarcmd, {}, function(err, stdout, stderr) {
          if (err && !(options.ignoreFileChangedError && err.code === 1 && stderr.match(/file changed as we read it/i))) {
            log.err(sprintf('Creating tarball failed: (%s) %s\nCommand was: %s', err.code, stderr, tarcmd));
            return handleError(new Error(sprintf('Creating tarball failed: %s', stderr)));
          }

          log.info(sprintf('Successfully created tarball: %s', tarballName));
          setTimeout(callback, 100);
        });
      });
    }
  );
};

/**
 * Return an array of files and directories in a tarball.
 *
 * @param {String} tarballPath Path to the tarball.
 * @param {Function} callback A callback called with a possible error as the first argument and an array
 *                            with all the files and directories in an archive as the second argument on success.
 *
 */
exports.getTarballFileList = function(tarballPath, callback) {
  var fileList = [];

  norris.get(function(facts) {
    var tarcmd = sprintf('%s tvf "%s"', facts.gnutar, tarballPath);
    var tar = exec(tarcmd, function(err, stdout, stderr) {
      var line, match;

      if (err) {
        callback(err, null);
        return;
      }

      var lines = stdout.split(/\n\r?/g);

      for (var i = 0; i < lines.length; i++) {
        line = lines[i];
        match = line.match(/^.*\s(.*?)$/);

        if (match) {
          fileList.push(match[1].trim());
        }
      }

      callback(null, fileList);
    });
  });
};
<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');

/**
 * Loads / require js file from specified `dir`.
 * Relative to `rootDir`
 * @param  {String} dir                    Loads all js files from this directory.
 * @param  {String} [rootDir=process.cwd(] Relative to this directory
 */
exports.loadJS = function (dir, rootDir = process.cwd()) {
  const loadedJS = [];
  const loadDir = path.resolve(rootDir, dir);
  if (fs.existsSync(loadDir)) {
    const modelFiles = fs.readdirSync(loadDir);
    modelFiles.forEach(p =>
      p.length - p.lastIndexOf('.js') === 3 && loadedJS.push(require(path.resolve(loadDir, p))));
  }
};
<commit_msg>Update jsUtil.js<commit_after>const fs = require('fs');
const path = require('path');

/**
 * Loads / require js file from specified `dir`.
 * Relative to `rootDir`
 * @param  {String} dir                    Loads all js files from this directory.
 * @param  {String} [rootDir=process.cwd(] Relative to this directory
 */
exports.loadJS = function (dir, rootDir = process.cwd()) {
  const loadedJS = [];
  const loadDir = path.resolve(rootDir, dir);
  if (fs.existsSync(loadDir)) {
    const modelFiles = fs.readdirSync(loadDir);
    modelFiles.forEach(p =>
      p.length - p.lastIndexOf('.js') === 3 && loadedJS.push(require(path.resolve(loadDir, p))));
  }
  return loadedJS;
};
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const {Cc, Ci} = require("chrome");
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const winUtils = require("sdk/deprecated/window-utils");
const utils = require("sdk/window/utils");
const windowIterator = winUtils.windowIterator;
const keys =  require("../core/key");
const system = require("sdk/system");
const {Overlays} = require("../core/overlay");
const {Shortcut} = require("../core/shortcut");
if (45 > system.version) { var bug645371 = require("../patch/bug-645371"); }
else console.log("Firefox 45.0 or newer detected, excluding patch for bug-645371.")
var bug406199 = require("../patch/bug-406199");

let Windows = {
handleKeyPress: function (event) {
    let shortcut = Shortcut.fromEvent(event);
if (shortcut.key|| shortcut.keycode) {
    // check if this is a custom shortcut
    let overlay = Overlays.findByCustomShortcut(shortcut);

    if (overlay) { overlay.key.executeCommand(); }
    else { // check if this is a shortcut that is overriden by a custom one
    overlay = Overlays.findByOverriddenShortcut(shortcut);
    }
    if (overlay) {
        event.preventDefault();
        event.stopPropagation();
    }
    }
},
    addEventListener: function(type, callback) {
    const prefpane = require("../prefs/prefpane");
        for (let window of utils.windows(null, {includePrivate:true})) {
        if ("undefined" != typeof(bug645371)) { bug645371.applyPatch(utils.getToplevelWindow(window)); }
        if ("undefined" != typeof(bug406199)) { bug406199.applyPatch(utils.getToplevelWindow(window)); }
                if ("main-window" == window.document.documentElement.getAttribute("id")) {
            if (!require("sdk/private-browsing").isPrivate(utils.getToplevelWindow(window))) {// Do not allow access to preferences in Private Windows.
				prefpane.createNewMenuItem(window);
        	}
        }
        window.addEventListener(type, callback, false);

        listeners.push({
            type: type,
            callback: callback
        });
    }
    },

    removeEventListener: function(type, callback) {
        for (let window of utils.windows(null, {includePrivate:true})) {
        window.removeEventListener(type, callback, false);

        	for (let i of ["sep-switch-tabs","ttshortcutsMenuItem","prevTab-command","nextTab-command"]) {
				let node = window.document.getElementById(i);
				if (node) {
			  		node.parentNode.removeChild(node);
				}
			}

        }

        listeners = listeners.filter(function(listener) {
            return !(type == listener.type && callback == listener.callback);
        });
     },

    toggleKey: function(key, state) {
        let id = "#" + key;
        for (let window of utils.windows(null, {includePrivate:true})) {
            if (utils.isBrowser(window)) {
                let keyToToggle = window.document.documentElement.querySelector(id);
                keyToToggle.setAttribute("disabled", state);
            }
        }
    },

    disableKeys: function() {
        let disabledOverlay = Object.keys(Overlays.overlays.disabled);

        if (disabledOverlay.length > 0) {
            let disabledSelector = "#" + disabledOverlay.join(", #");

            for (let window of utils.windows(null, {includePrivate:true})) {
                if (utils.isBrowser(window)) {
                    let disabledKeys = window.document.documentElement.querySelectorAll(disabledSelector);

                    for (let dkey = 0; dkey < disabledKeys.length; dkey++) {
                        disabledKeys[dkey].setAttribute("disabled", "true");
                    }
                }
            }
        }
    },

    getMostRecentWindow: function() {
        return winUtils.activeBrowserWindow;
    },
    getElementById: function(id) {
        return Windows.getMostRecentWindow().document.getElementById(id);
    },

    querySelector: function(sel) {
        return Windows.getMostRecentWindow().document.querySelector(sel);
    },

    querySelectorAll: function(sel) {
        return Windows.getMostRecentWindow().document.querySelectorAll(sel);
    },

    createEvent: function(type) {
        return Windows.getMostRecentWindow().document.createEvent(type);
    },

    createXulElement: function(tagName, attrs, parent) {
        let element = Windows.getMostRecentWindow().document.createElementNS(XUL_NS, tagName);

        if (attrs) {
            for (let name in attrs)
            element.setAttribute(name, attrs[name]);
        }

        if (parent) parent.appendChild(element);

        return element;
    }
};

new winUtils.WindowTracker({
    onTrack: function(window) {
        if (utils.isBrowser(window)) {
            Windows.addEventListener("keydown", Windows.handleKeyPress, false);
            Overlays._overlays && Windows.disableKeys();
        }
    },

    onUntrack: function(window) {
        if (utils.isBrowser(window)) {
                Windows.removeEventListener("keydown", Windows.handleKeyPress, false);
        }
    }
});

exports.Windows = Windows;
<commit_msg>Get rid of "listeners" array<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const {Cc, Ci} = require("chrome");
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const winUtils = require("sdk/deprecated/window-utils");
const utils = require("sdk/window/utils");
const windowIterator = winUtils.windowIterator;
const keys =  require("../core/key");
const system = require("sdk/system");
const {Overlays} = require("../core/overlay");
const {Shortcut} = require("../core/shortcut");
if (45 > system.version) { var bug645371 = require("../patch/bug-645371"); }
else console.log("Firefox 45.0 or newer detected, excluding patch for bug-645371.")
var bug406199 = require("../patch/bug-406199");

let Windows = {
handleKeyPress: function (event) {
    let shortcut = Shortcut.fromEvent(event);
if (shortcut.key|| shortcut.keycode) {
    // check if this is a custom shortcut
    let overlay = Overlays.findByCustomShortcut(shortcut);

    if (overlay) { overlay.key.executeCommand(); }
    else { // check if this is a shortcut that is overriden by a custom one
    overlay = Overlays.findByOverriddenShortcut(shortcut);
    }
    if (overlay) {
        event.preventDefault();
        event.stopPropagation();
    }
    }
},
    addEventListener: function(type, callback) {
    const prefpane = require("../prefs/prefpane");
        for (let window of utils.windows(null, {includePrivate:true})) {
        if ("undefined" != typeof(bug645371)) { bug645371.applyPatch(utils.getToplevelWindow(window)); }
        if ("undefined" != typeof(bug406199)) { bug406199.applyPatch(utils.getToplevelWindow(window)); }
                if ("main-window" == window.document.documentElement.getAttribute("id")) {
            if (!require("sdk/private-browsing").isPrivate(utils.getToplevelWindow(window))) {// Do not allow access to preferences in Private Windows.
				prefpane.createNewMenuItem(window);
        	}
        }
        window.addEventListener(type, callback, false);
    }
    },

    removeEventListener: function(type, callback) {
        for (let window of utils.windows(null, {includePrivate:true})) {
        window.removeEventListener(type, callback, false);

        	for (let i of ["sep-switch-tabs","ttshortcutsMenuItem","prevTab-command","nextTab-command"]) {
				let node = window.document.getElementById(i);
				if (node) {
			  		node.parentNode.removeChild(node);
				}
			}

        }
     },

    toggleKey: function(key, state) {
        let id = "#" + key;
        for (let window of utils.windows(null, {includePrivate:true})) {
            if (utils.isBrowser(window)) {
                let keyToToggle = window.document.documentElement.querySelector(id);
                keyToToggle.setAttribute("disabled", state);
            }
        }
    },

    disableKeys: function() {
        let disabledOverlay = Object.keys(Overlays.overlays.disabled);

        if (disabledOverlay.length > 0) {
            let disabledSelector = "#" + disabledOverlay.join(", #");

            for (let window of utils.windows(null, {includePrivate:true})) {
                if (utils.isBrowser(window)) {
                    let disabledKeys = window.document.documentElement.querySelectorAll(disabledSelector);

                    for (let dkey = 0; dkey < disabledKeys.length; dkey++) {
                        disabledKeys[dkey].setAttribute("disabled", "true");
                    }
                }
            }
        }
    },

    getMostRecentWindow: function() {
        return winUtils.activeBrowserWindow;
    },
    getElementById: function(id) {
        return Windows.getMostRecentWindow().document.getElementById(id);
    },

    querySelector: function(sel) {
        return Windows.getMostRecentWindow().document.querySelector(sel);
    },

    querySelectorAll: function(sel) {
        return Windows.getMostRecentWindow().document.querySelectorAll(sel);
    },

    createEvent: function(type) {
        return Windows.getMostRecentWindow().document.createEvent(type);
    },

    createXulElement: function(tagName, attrs, parent) {
        let element = Windows.getMostRecentWindow().document.createElementNS(XUL_NS, tagName);

        if (attrs) {
            for (let name in attrs)
            element.setAttribute(name, attrs[name]);
        }

        if (parent) parent.appendChild(element);

        return element;
    }
};

new winUtils.WindowTracker({
    onTrack: function(window) {
        if (utils.isBrowser(window)) {
            Windows.addEventListener("keydown", Windows.handleKeyPress, false);
            Overlays._overlays && Windows.disableKeys();
        }
    },

    onUntrack: function(window) {
        if (utils.isBrowser(window)) {
                window.removeEventListener("keydown", Windows.handleKeyPress, false);
        }
    }
});

exports.Windows = Windows;
<|endoftext|>


<commit_before>export function fillGaps ( target, ...sources ) {

	for (let i = 0; i < sources.length; i++){
		const source = sources[i];
		for ( const key in source ) {
			if ( !source.hasOwnProperty(key) || key in target ) continue;
			target[ key ] = source[ key ];
		}
	}

	return target;
}

export function toPairs ( obj = {} ) {
	const pairs = [];
	for ( const key in obj ) {
		if ( !obj.hasOwnProperty( key ) ) continue;
		pairs.push( [ key, obj[ key ] ] );
	}
	return pairs;
}
<commit_msg>Guard against prototype-less objects on object util functions<commit_after>export function fillGaps ( target, ...sources ) {

	for (let i = 0; i < sources.length; i++){
		const source = sources[i];
		for ( const key in source ) {
			// Source can be a prototype-less object.
			if ( key in target || !Object.prototype.hasOwnProperty.call( source, key ) ) continue;
			target[ key ] = source[ key ];
		}
	}

	return target;
}

export function toPairs ( obj = {} ) {
	const pairs = [];
	for ( const key in obj ) {
		// Source can be a prototype-less object.
		if ( !Object.prototype.hasOwnProperty.call( obj, key ) ) continue;
		pairs.push( [ key, obj[ key ] ] );
	}
	return pairs;
}
<|endoftext|>


<commit_before>var util = require('util')
var arrayToMap = require('./array-to-map')

/**
 * Available types of errors
 */
var types = arrayToMap(['UnknownOption', 'InvalidKey'])

/**
 * Custom message for unknown cli option
 * @constructor UknownOptionError
 * @param {String} message? error message
 */
function UnknownOptionError(message) {
	this.type = types.UnknownOption
	this.message = message
}

// inherits builtin Error
util.inherits(UnknownOptionError, Error)

/**
 * Custom error for invalid cli option
 * @constructor InvalidKeyError
 * @param {String} message?
 */
function InvalidKeyError(message) {
	this.type = types.InvalidKey
	this.message = message
}

util.inherits(InvalidKeyError, Error)

module.exports = {
	errorTypes: types,
	InvalidKeyError: InvalidKeyError,
	UnknownOptionError: UnknownOptionError
}

<commit_msg>update utils/errors; use classes<commit_after>'use strict';

const arrayToMap = require('../-funcs').arrayToMap;

/**
 * Available types of errors
 */
const types = arrayToMap(['UnknownOption', 'InvalidKey']);

/**
 * Unknown CLI option.
 * @param {String} msg  Custom error message.
 */
class UnknownOptionError extends Error {
	constructor(msg) {
		this.type = types.UnknownOption;
		this.message = msg;
	}
}

/**
 * Custom error for invalid CLI option
 * @param {String} msg
 */
class InvalidKeyError extends Error {
	constructor(msg) {
		this.type = types.InvalidKey;
		this.message = msg;
	}
}

module.exports = {
	errorTypes: types,
	InvalidKeyError: InvalidKeyError,
	UnknownOptionError: UnknownOptionError
};
<|endoftext|>


<commit_before>module.exports = function finder(options, callback) {
  var is      = this.is;
  var string  = this.string;
  var assert  = this.assert;
  var glob    = this.glob.sync;
  var resolve = this.path.resolve;

  if(is.string(options)) {
    options = { pattern: options };
  }

  assert(is.object(options), 'Missing options');
  console.log(options.cwd);
  options.cwd = options.cwd || process.cwd();
  console.log(options.cwd);

  var files;
  var S = string(options.pattern);

  if(S.contains('*')) {
    files = glob(options.pattern, {
      cwd: options.cwd,
      mark: true
    });
  }
  else files = [resolve(options.cwd, options.pattern)];

  assert(!is.array.empty(files), 'No files were found');

  files.forEach(function(file) {
    callback(resolve(options.cwd, file), files.length);
  });

  return files;
};
<commit_msg>Remove debug<commit_after>module.exports = function finder(options, callback) {
  var is      = this.is;
  var string  = this.string;
  var assert  = this.assert;
  var glob    = this.glob.sync;
  var resolve = this.path.resolve;

  if(is.string(options)) {
    options = { pattern: options };
  }

  assert(is.object(options), 'Missing options');
  options.cwd = options.cwd || process.cwd();

  var files;
  var S = string(options.pattern);

  if(S.contains('*')) {
    files = glob(options.pattern, {
      cwd: options.cwd,
      mark: true
    });
  }
  else files = [resolve(options.cwd, options.pattern)];

  assert(!is.array.empty(files), 'No files were found');

  files.forEach(function(file) {
    callback(resolve(options.cwd, file), files.length);
  });

  return files;
};
<|endoftext|>


<commit_before>/* global docma */
/* eslint no-nested-ternary:0 */

// docma.dom
// https://github.com/onury/docma
(function () {

    // --------------------------------
    // DOM METHODS
    // --------------------------------

    var dom = {};

    /**
     *  Creates and appends a child DOM element to the target, from the given
     *  element definition.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {HTMLElement} target
     *         Target container element.
     *  @param {String} [type="div"]
     *         Type of the element to be appended.
     *  @param {Object} [attrs]
     *         Element attributes.
     *
     *  @returns {HTMLElement} - Appended element.
     */
    dom.createChild = function (target, type, attrs) {
        attrs = attrs || {};
        var el = document.createElement(type || 'div');
        Object.keys(attrs).forEach(function (key) {
            el[key] = attrs[key]; // e.g. id, innerHTML, etc...
        });
        target.appendChild(el);
        return el;
    };

    /**
     *  Gets Docma main DOM element which the Dust templates will be rendered
     *  into.
     *  @private
     *  @memberof docma.dom
     *
     *  @returns {HTMLElement} - Docma main DOM element.
     */
    dom.getDocmaElem = function () {
        var docmaElem = document.getElementById(docma._.elementID);
        if (!docmaElem) {
            docmaElem = dom.createChild(document.body, 'div', {
                id: docma._.elementID
            });
        }
        return docmaElem;
    };

    /**
     *  Gets Docma content DOM element that the HTML content will be loaded
     *  into. This should be called for `docma-content` partial.
     *  @private
     *  @memberof docma.dom
     *
     *  @returns {HTMLElement} - Docma content DOM element.
     */
    dom.getContentElem = function () {
        // docma-content template (should) have a
        //

 element whithin.
        var dContent = document.getElementById(docma._.contentElementID);
        if (!dContent) {
            // this is fatal, so we always throw if invalid content partial
            // TODO: this should be checked during build process
            throw new Error('Partial ' + docma._.partials.content + ' should have an element with id="' + docma._.contentElementID + '".');
        }
        return dContent;
    };

    /**
     *  Loads dust-compiled HTML content into `docma-main` element.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {String} compiledHTML - Dust-compiled HTML content.
     */
    dom.loadCompiledContent = function (compiledHTML) {
        // load compiled content into

        var docmaElem = dom.getDocmaElem();
        docmaElem.innerHTML = compiledHTML;
        // dom.fixAnchors();
    };

    /**
     *  Loads the given HTML content into `docma-content` element.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {String} html - Content to be loaded.
     */
    dom.loadContent = function (html) {
        var dContent = dom.getContentElem();
        dContent.innerHTML = html;
        // dom.fixAnchors();
        dom.scrollTo(); // top
    };

    /**
     *  Gets the offset coordinates of the given element, relative to document
     *  body.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {HTMLElement} e - Target element.
     */
    dom.getOffset = function (e) {
        var elem = typeof e === 'object' ? e : document.getElementById(e);
        if (!elem) return;
        var rect = elem.getBoundingClientRect();
        // Make sure element is not hidden (display: none) or disconnected
        if (rect.width || rect.height || elem.getClientRects().length) {
            var docElem = document.documentElement;
            return {
                top: rect.top + window.pageYOffset - docElem.clientTop,
                left: rect.left + window.pageXOffset - docElem.clientLeft
            };
        }
    };

    /**
     *  Scrolls the document to the given hash target.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {String} [hash] - Bookmark target. If omitted, document is
     *  scrolled to the top.
     */
    dom.scrollTo = function (hash) {
        hash = (hash || window.location.hash || '').replace(/^#/, '');
        if (!hash) {
            document.body.scrollTop = 0;
            return;
        }
        var elem = document.getElementById(hash);
        if (!elem) return;
        document.body.scrollTop = dom.getOffset(elem).top;
    };

    /**
     *  Fixes the base+hash issue. When base tag is set in the head of an HTML,
     *  bookmark anchors will navigate to the base URL with a hash; even with
     *  sub paths. This will fix that behaviour.
     *  @private
     *  @memberof docma.dom
     *
     *  @returns {void}
     */
    dom.fixAnchors = function () {
        if (docma.app.base) {
            setTimeout(function () {
                var i, el,
                    nodes = document.querySelectorAll('a[href^="#"');
                for (i = 0; i < nodes.length; i++) {
                    el = nodes[i];
                    var href = el.getAttribute('href');
                    if (href.slice(0, 1) === '#') {
                        href = window.location.pathname + (window.location.search || '') + href;
                        el.setAttribute('href', href);
                    }
                }
            }, 50);
        }
    };

    // --------------------------------

    /**
     *  Utilities for Docma DOM operations.
     *  @namespace
     *  @private
     */
    docma.dom = Object.freeze(dom);

})();
<commit_msg>fix querySelectorAll selector<commit_after>/* global docma */
/* eslint no-nested-ternary:0 */

// docma.dom
// https://github.com/onury/docma
(function () {

    // --------------------------------
    // DOM METHODS
    // --------------------------------

    var dom = {};

    /**
     *  Creates and appends a child DOM element to the target, from the given
     *  element definition.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {HTMLElement} target
     *         Target container element.
     *  @param {String} [type="div"]
     *         Type of the element to be appended.
     *  @param {Object} [attrs]
     *         Element attributes.
     *
     *  @returns {HTMLElement} - Appended element.
     */
    dom.createChild = function (target, type, attrs) {
        attrs = attrs || {};
        var el = document.createElement(type || 'div');
        Object.keys(attrs).forEach(function (key) {
            el[key] = attrs[key]; // e.g. id, innerHTML, etc...
        });
        target.appendChild(el);
        return el;
    };

    /**
     *  Gets Docma main DOM element which the Dust templates will be rendered
     *  into.
     *  @private
     *  @memberof docma.dom
     *
     *  @returns {HTMLElement} - Docma main DOM element.
     */
    dom.getDocmaElem = function () {
        var docmaElem = document.getElementById(docma._.elementID);
        if (!docmaElem) {
            docmaElem = dom.createChild(document.body, 'div', {
                id: docma._.elementID
            });
        }
        return docmaElem;
    };

    /**
     *  Gets Docma content DOM element that the HTML content will be loaded
     *  into. This should be called for `docma-content` partial.
     *  @private
     *  @memberof docma.dom
     *
     *  @returns {HTMLElement} - Docma content DOM element.
     */
    dom.getContentElem = function () {
        // docma-content template (should) have a
        //

 element whithin.
        var dContent = document.getElementById(docma._.contentElementID);
        if (!dContent) {
            // this is fatal, so we always throw if invalid content partial
            // TODO: this should be checked during build process
            throw new Error('Partial ' + docma._.partials.content + ' should have an element with id="' + docma._.contentElementID + '".');
        }
        return dContent;
    };

    /**
     *  Loads dust-compiled HTML content into `docma-main` element.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {String} compiledHTML - Dust-compiled HTML content.
     */
    dom.loadCompiledContent = function (compiledHTML) {
        // load compiled content into

        var docmaElem = dom.getDocmaElem();
        docmaElem.innerHTML = compiledHTML;
        // dom.fixAnchors();
    };

    /**
     *  Loads the given HTML content into `docma-content` element.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {String} html - Content to be loaded.
     */
    dom.loadContent = function (html) {
        var dContent = dom.getContentElem();
        dContent.innerHTML = html;
        // dom.fixAnchors();
        dom.scrollTo(); // top
    };

    /**
     *  Gets the offset coordinates of the given element, relative to document
     *  body.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {HTMLElement} e - Target element.
     */
    dom.getOffset = function (e) {
        var elem = typeof e === 'object' ? e : document.getElementById(e);
        if (!elem) return;
        var rect = elem.getBoundingClientRect();
        // Make sure element is not hidden (display: none) or disconnected
        if (rect.width || rect.height || elem.getClientRects().length) {
            var docElem = document.documentElement;
            return {
                top: rect.top + window.pageYOffset - docElem.clientTop,
                left: rect.left + window.pageXOffset - docElem.clientLeft
            };
        }
    };

    /**
     *  Scrolls the document to the given hash target.
     *  @private
     *  @memberof docma.dom
     *
     *  @param {String} [hash] - Bookmark target. If omitted, document is
     *  scrolled to the top.
     */
    dom.scrollTo = function (hash) {
        hash = (hash || window.location.hash || '').replace(/^#/, '');
        if (!hash) {
            document.body.scrollTop = 0;
            return;
        }
        var elem = document.getElementById(hash);
        if (!elem) return;
        document.body.scrollTop = dom.getOffset(elem).top;
    };

    /**
     *  Fixes the base+hash issue. When base tag is set in the head of an HTML,
     *  bookmark anchors will navigate to the base URL with a hash; even with
     *  sub paths. This will fix that behaviour.
     *  @private
     *  @memberof docma.dom
     *
     *  @returns {void}
     */
    dom.fixAnchors = function () {
        if (docma.app.base) {
            setTimeout(function () {
                var i, el,
                    nodes = document.querySelectorAll('a[href^="#"]');
                for (i = 0; i < nodes.length; i++) {
                    el = nodes[i];
                    var href = el.getAttribute('href');
                    if (href.slice(0, 1) === '#' && href.length > 1) {
                        href = window.location.pathname + (window.location.search || '') + href;
                        el.setAttribute('href', href);
                    }
                }
            }, 50);
        }
    };

    // --------------------------------

    /**
     *  Utilities for Docma DOM operations.
     *  @namespace
     *  @private
     */
    docma.dom = Object.freeze(dom);

})();
<|endoftext|>


<commit_before>const xlsx = require('node-xlsx');
const fs = require('fs');
const path = require('path');
// const moment = require('moment');

let arraySeparator;

/**
 * sheet(table) 的类型
 * 影响输出json的类型
 * 当有#id类型的时候  表输出json的是map形式(id:{xx:1})
 * 当没有#id类型的时候  表输出json的是数组类型 没有id索引
 */
const SheetType = {
  /**
   * 普通表
   */
  NORMAL: 0,

  /**
   * 有主外键关系的主表
   * primary key
   */
  PRIMARY: 1,

  /**
   * 有主外键关系的附表
   * foreign key
   */
  FOREIGN: 2
};

/**
 * 支持的数据类型
 */
const DataType = {
  NUMBER: 'number',
  STRING: 'string',
  BOOL: 'bool',
  DATE: 'date',
  ID: 'id',
  ARRAY: '[]',
  OBJECT: '{}',
  OBJECT_ARRAY: '[{}]',
  UNKOWN: 'unkown'
};

module.exports = {

  /**
   * convert xlsx file to json and save it to file system.
   * @param  {String} src path of .xlsx files.
   * @param  {String} dest       directory for exported json files.
   * @param  {Number} headIndex      index of head line.
   * @param  {String} separator      array separator.
   *
   * excel structure
   * workbook > worksheet > table(row column)
   */
  toJson: function(src, dest, config) {

    let headIndex = config.xlsx.head - 1;
    arraySeparator = config.xlsx.arraySeparator;
    let uglifyJson = config.json.uglify;

    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest);
    }

    console.log("parsing excel:", src);

    let workbook = xlsx.parse(src);
    parseWorkbook(workbook, dest, headIndex, uglifyJson);
  }
};

/**
 * convert worksheet in workbook and save to file for each.
 * @param       {[Object]} workbook json object of excel's workbook.
 * @param       {[String]} dest     directory for exported json files.
 * @param       {[Number]} headIndex     index of head line.
 */
function parseWorkbook(workbook, dest, headIndex, uglifyJson) {

  workbook.forEach(sheet => {

    // ignore sheet with external keys only, or start with a '#'
    if (sheet.name.indexOf('@') === -1 && sheet.name[0] !== "#") {
      let parsedSheet = parseSheet(sheet, headIndex);

      let dest_file = path.resolve(dest, sheet.name + ".json");
      let formatedJson = JSON.stringify(parsedSheet, null, uglifyJson ? 0 : 2); //, null, 2
      fs.writeFile(dest_file, formatedJson, err => {
        if (err) {
          console.error("error：", err);
          throw err;
        }
        console.log('exported successfully  -->  ', path.basename(dest_file));
      });
    }
  });
}

/**
 * parse one sheet and return the result as a json object or array
 *
 * @param sheet
 * @param headIndex
 * @private
 */
function parseSheet(sheet, headIndex) {

  console.log('\t parsing sheet', sheet.name);

  if (sheet && sheet.data) {

    let head = parseHead(sheet, headIndex);

    let result = [];

    for (let i_row = headIndex + 1; i_row < sheet.data.length; i_row++) {

      let row = sheet.data[i_row];

      let parsedRow = parseRow(row, i_row, head);
      result.push(parsedRow);
    }
    return result;
  }
}

function parseHead(sheet, headIndex) {

  let headRow = sheet.data[headIndex];

  // console.log("\t\t parsing head", headIndex, headRow);

  let head = {
    names: [], //所有名字 json的key
    types: [], //所有列的数据类型
    index: headIndex, //表头所在的行索引
    sheetType: SheetType.NORMAL //表类型 普通表  主表 引用表
  };

  headRow.forEach(cell => {
    let type = DataType.UNKOWN;
    let name = cell;

    if ((cell + '').indexOf('#') !== -1) {
      let pair = cell.split('#');
      name = pair[0].trim();
      type = pair[1].toLowerCase().trim();
      if (type === DataType.ID) {
        head.sheetType = SheetType.PRIMARY;
      }
    }

    head.types.push(type);
    head.names.push(name);
  });

  return head;
}

function parseRow(row, rowIndex, head) {

  let result = {};
  let id;

  row.forEach((cell, index) => {

    if (cell) {

      let name = head.names[index];
      let type = head.types[index];

      switch (type) {
        case DataType.ID: // number string boolean
          if (isNumber(cell)) {
            id = Number(cell);
          } else {
            id = cell;
          }
          result[name] = id;
          break;
        case DataType.UNKOWN: // number string boolean
          if (isNumber(cell)) {
            result[name] = Number(cell);
          } else if (isBoolean(cell)) {
            result[name] = toBoolean(cell);
          } else {
            result[name] = cell;
          }
          break;
        case DataType.DATE:
          if (isNumber(cell)) {
            //xlsx's bug!!!
            result[name] = numdate(cell);
          } else {
            result[name] = cell.toString();
          }
          break;
        case DataType.STRING:
          result[name] = cell.toString();
          break;
        case DataType.NUMBER:
          //+xxx.toString() '+' means convert it to number
          if (isNumber(cell)) {
            result[name] = Number(cell);
          } else {
            console.warn("type error at [" + rowIndex + "," + index + "]," + cell + " is not a number");
          }
          break;
        case DataType.BOOL:
          result[name] = toBoolean(cell);
          break;
        case DataType.OBJECT: //support {number boolean string date} property type
          result[name] = array2object(cell.split(';'));
          break;
        case DataType.ARRAY: //[number] [boolean] [string]  todo:support [date] type
          result[name] = parseBasicArrayField(cell, arraySeparator);
          break;
        case DataType.OBJECT_ARRAY:
          result[name] = parseObjectArrayField(cell);
          break;
        default:
          // foo#[]| 处理自定义数组分隔符
          if (type.indexOf(DataType.ARRAY) !== -1) {
            // if (!type.endsWith(DataType.ARRAY)) {
            let separator = type.substr(-1, 1); //get the last character
            result[name] = parseBasicArrayField(cell, separator);
            // }
          } else {
            console.log('unrecognized type', '[' + rowIndex + ',' + index + ']', cell, typeof(cell));
          }
          break;
      }
    }
  });

  switch (head.sheetType) {
    case SheetType.NORMAL: //json以数组的格式输出
      return result;
    case SheetType.PRIMARY: //json以map的格式输出
      let map = {};
      map[id] = result;
      return map;
    default:
      throw '无法识别表格类型!';
  }

  // return result;
}

/**
 * parse object array.
 */
function parseObjectArrayField(value) {

  let obj_array = [];

  if (value) {
    if (value.indexOf(',') !== -1) {
      obj_array = value.split(',');
    } else {
      obj_array.push(value.toString());
    }
  }

  // if (typeof(value) === 'string' && value.indexOf(',') !== -1) {
  //     obj_array = value.split(',');
  // } else {
  //     obj_array.push(value.toString());
  // };

  let result = [];

  obj_array.forEach(function(e) {
    if (e) {
      result.push(array2object(e.split(';')));
    }
  });

  // row[key] = result;
  return result;
}

/**
 * parse object from array.
 *  for example : [a:123,b:45] => {'a':123,'b':45}
 */
function array2object(array) {
  let result = {};
  array.forEach(function(e) {
    if (e) {
      let colonIndex = e.indexOf(':');
      let key = e.substring(0, colonIndex);
      let value = e.substring(colonIndex + 1);
      if (isNumber(value)) {
        value = Number(value);
      } else if (isBoolean(value)) {
        value = toBoolean(value);
      }
      result[key] = value;
    }
  });
  return result;
}

/**
 * parse simple array.
 */
function parseBasicArrayField(array,arraySeparator) {
  let basic_array;

  if (typeof array === "string") {
    basic_array = array.split(arraySeparator);
  } else {
    basic_array = [];
    basic_array.push(array);
  }

  let result = [];
  if (isNumberArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(Number(element));
    });
  } else if (isBooleanArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(toBoolean(element));
    });
  } else { //string array
    result = basic_array;
  }
  // console.log("basic_array", result + "|||" + cell.value);
  // field[key] = result;
  return result;
}

/**
 * convert value to boolean.
 */
function toBoolean(value) {
  return value.toString().toLowerCase() === 'true';
}

/**
 * is a boolean array.
 */
function isBooleanArray(arr) {
  return arr.every(function(element, index, array) {
    return isBoolean(element);
  });
}

/**
 * is a number array.
 */
function isNumberArray(arr) {
  return arr.every(function(element, index, array) {
    return isNumber(element);
  });
}

/**
 * is a number.
 */
function isNumber(value) {

  if (value) {
    if (typeof value === 'number') {
      return true;
    }
    return !isNaN(+value.toString());
  }

  return false;
}

/**
 * boolean type check.
 */
function isBoolean(value) {

  if (typeof(value) === "undefined") {
    return false;
  }

  if (typeof value === 'boolean') {
    return true;
  }

  let b = value.toString().trim().toLowerCase();

  return b === 'true' || b === 'false';
}

/**
 * date type check.
 */
// function isDateType(value) {
//   if (isNumber(value)) {
//     return false;
//   }
//   if (value) {
//     return moment(new Date(value), "YYYY-M-D", true).isValid() || moment(value, "YYYY-M-D H:m:s", true).isValid() || moment(value, "YYYY/M/D H:m:s", true).isValid() || moment(value, "YYYY/M/D", true).isValid();
//   }
//   return false;
// }

//fuck xlsx's bug
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
// var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
// function datenum(v, date1904) {
// 	var epoch = v.getTime();
// 	if(date1904) epoch -= 1462*24*60*60*1000;
// 	return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
// }

function numdate(v) {
  var out = new Date();
  out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
  return out;
}
//fuck over
<commit_msg>bugfix:#id type data wrapped in object<commit_after>const xlsx = require('node-xlsx');
const fs = require('fs');
const path = require('path');
// const moment = require('moment');

let arraySeparator;

/**
 * sheet(table) 的类型
 * 影响输出json的类型
 * 当有#id类型的时候  表输出json的是map形式(id:{xx:1})
 * 当没有#id类型的时候  表输出json的是数组类型 没有id索引
 */
const SheetType = {
  /**
   * 普通表
   */
  NORMAL: 0,

  /**
   * 有主外键关系的主表
   * primary key
   */
  PRIMARY: 1,

  /**
   * 有主外键关系的附表
   * foreign key
   */
  FOREIGN: 2
};

/**
 * 支持的数据类型
 */
const DataType = {
  NUMBER: 'number',
  STRING: 'string',
  BOOL: 'bool',
  DATE: 'date',
  ID: 'id',
  ARRAY: '[]',
  OBJECT: '{}',
  OBJECT_ARRAY: '[{}]',
  UNKOWN: 'unkown'
};

module.exports = {

  /**
   * convert xlsx file to json and save it to file system.
   * @param  {String} src path of .xlsx files.
   * @param  {String} dest       directory for exported json files.
   * @param  {Number} headIndex      index of head line.
   * @param  {String} separator      array separator.
   *
   * excel structure
   * workbook > worksheet > table(row column)
   */
  toJson: function(src, dest, config) {

    let headIndex = config.xlsx.head - 1;
    arraySeparator = config.xlsx.arraySeparator;
    let uglifyJson = config.json.uglify;

    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest);
    }

    console.log("parsing excel:", src);

    let workbook = xlsx.parse(src);
    parseWorkbook(workbook, dest, headIndex, uglifyJson);
  }
};

/**
 * convert worksheet in workbook and save to file for each.
 * @param       {[Object]} workbook json object of excel's workbook.
 * @param       {[String]} dest     directory for exported json files.
 * @param       {[Number]} headIndex     index of head line.
 */
function parseWorkbook(workbook, dest, headIndex, uglifyJson) {

  workbook.forEach(sheet => {

    // ignore sheet with external keys only, or start with a '#'
    if (sheet.name.indexOf('@') === -1 && sheet.name[0] !== "#") {
      let parsedSheet = parseSheet(sheet, headIndex);

      let dest_file = path.resolve(dest, sheet.name + ".json");
      let formatedJson = JSON.stringify(parsedSheet, null, uglifyJson ? 0 : 2); //, null, 2
      fs.writeFile(dest_file, formatedJson, err => {
        if (err) {
          console.error("error：", err);
          throw err;
        }
        console.log('exported successfully  -->  ', path.basename(dest_file));
      });
    }
  });
}

/**
 * parse one sheet and return the result as a json object or array
 *
 * @param sheet
 * @param headIndex
 * @private
 */
function parseSheet(sheet, headIndex) {

  console.log('\t parsing sheet', sheet.name);

  if (sheet && sheet.data) {

    let head = parseHead(sheet, headIndex);

    let result;

    if (head.sheetType === SheetType.NORMAL) {
      result = [];
    } else if (head.sheetType === SheetType.PRIMARY) {
      result = {};
    }

    for (let i_row = headIndex + 1; i_row < sheet.data.length; i_row++) {

      let row = sheet.data[i_row];

      let parsedRow = parseRow(row, i_row, head);
      if (head.sheetType === SheetType.NORMAL) { ////json以数组的格式输出
        result.push(parsedRow);
      } else if (head.sheetType === SheetType.PRIMARY) { //json以map的格式输出
        let id = parsedRow[head.getIdKey()];
        result[id] = parsedRow;
      } else {
        throw '无法识别表格类型!';
      }
    }
    return result;
  }
}

function parseHead(sheet, headIndex) {

  let headRow = sheet.data[headIndex];

  // console.log("\t\t parsing head", headIndex, headRow);

  let head = {
    //所有名字 json的key
    names: [],

    //所有列的数据类型
    types: [],

    //表头所在的行索引
    index: headIndex,

    //表类型 普通表  主表 引用表
    sheetType: SheetType.NORMAL,

    getIdKey:function(){
      let id_col_index = this.types.indexOf(DataType.ID);
      if(id_col_index < 0){
        throw '获取不到id列的名字';
      }
      return this.names[id_col_index];
    }
  };

  headRow.forEach(cell => {
    let type = DataType.UNKOWN;
    let name = cell;

    if ((cell + '').indexOf('#') !== -1) {
      let pair = cell.split('#');
      name = pair[0].trim();
      type = pair[1].toLowerCase().trim();
      if (type === DataType.ID) {
        head.sheetType = SheetType.PRIMARY;
      }
    }

    head.types.push(type);
    head.names.push(name);
  });

  return head;
}

function parseRow(row, rowIndex, head) {

  let result = {};
  let id;

  row.forEach((cell, index) => {

    if (cell) {

      let name = head.names[index];
      let type = head.types[index];

      switch (type) {
        case DataType.ID: // number string boolean
          if (isNumber(cell)) {
            id = Number(cell);
          } else {
            id = cell;
          }
          result[name] = id;
          break;
        case DataType.UNKOWN: // number string boolean
          if (isNumber(cell)) {
            result[name] = Number(cell);
          } else if (isBoolean(cell)) {
            result[name] = toBoolean(cell);
          } else {
            result[name] = cell;
          }
          break;
        case DataType.DATE:
          if (isNumber(cell)) {
            //xlsx's bug!!!
            result[name] = numdate(cell);
          } else {
            result[name] = cell.toString();
          }
          break;
        case DataType.STRING:
          result[name] = cell.toString();
          break;
        case DataType.NUMBER:
          //+xxx.toString() '+' means convert it to number
          if (isNumber(cell)) {
            result[name] = Number(cell);
          } else {
            console.warn("type error at [" + rowIndex + "," + index + "]," + cell + " is not a number");
          }
          break;
        case DataType.BOOL:
          result[name] = toBoolean(cell);
          break;
        case DataType.OBJECT: //support {number boolean string date} property type
          result[name] = array2object(cell.split(';'));
          break;
        case DataType.ARRAY: //[number] [boolean] [string]  todo:support [date] type
          result[name] = parseBasicArrayField(cell, arraySeparator);
          break;
        case DataType.OBJECT_ARRAY:
          result[name] = parseObjectArrayField(cell);
          break;
        default:
          // foo#[]| 处理自定义数组分隔符
          if (type.indexOf(DataType.ARRAY) !== -1) {
            // if (!type.endsWith(DataType.ARRAY)) {
            let separator = type.substr(-1, 1); //get the last character
            result[name] = parseBasicArrayField(cell, separator);
            // }
          } else {
            console.log('unrecognized type', '[' + rowIndex + ',' + index + ']', cell, typeof(cell));
          }
          break;
      }
    }
  });

  return result;

  // switch (head.sheetType) {
  //   case SheetType.NORMAL: //json以数组的格式输出
  //     return result;
  //   case SheetType.PRIMARY: //json以map的格式输出
  //     let map = {};
  //     map[id] = result;
  //     return map;
  //   default:
  //     throw '无法识别表格类型!';
  // }

  // return result;
}

/**
 * parse object array.
 */
function parseObjectArrayField(value) {

  let obj_array = [];

  if (value) {
    if (value.indexOf(',') !== -1) {
      obj_array = value.split(',');
    } else {
      obj_array.push(value.toString());
    }
  }

  // if (typeof(value) === 'string' && value.indexOf(',') !== -1) {
  //     obj_array = value.split(',');
  // } else {
  //     obj_array.push(value.toString());
  // };

  let result = [];

  obj_array.forEach(function(e) {
    if (e) {
      result.push(array2object(e.split(';')));
    }
  });

  // row[key] = result;
  return result;
}

/**
 * parse object from array.
 *  for example : [a:123,b:45] => {'a':123,'b':45}
 */
function array2object(array) {
  let result = {};
  array.forEach(function(e) {
    if (e) {
      let colonIndex = e.indexOf(':');
      let key = e.substring(0, colonIndex);
      let value = e.substring(colonIndex + 1);
      if (isNumber(value)) {
        value = Number(value);
      } else if (isBoolean(value)) {
        value = toBoolean(value);
      }
      result[key] = value;
    }
  });
  return result;
}

/**
 * parse simple array.
 */
function parseBasicArrayField(array, arraySeparator) {
  let basic_array;

  if (typeof array === "string") {
    basic_array = array.split(arraySeparator);
  } else {
    basic_array = [];
    basic_array.push(array);
  }

  let result = [];
  if (isNumberArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(Number(element));
    });
  } else if (isBooleanArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(toBoolean(element));
    });
  } else { //string array
    result = basic_array;
  }
  // console.log("basic_array", result + "|||" + cell.value);
  // field[key] = result;
  return result;
}

/**
 * convert value to boolean.
 */
function toBoolean(value) {
  return value.toString().toLowerCase() === 'true';
}

/**
 * is a boolean array.
 */
function isBooleanArray(arr) {
  return arr.every(function(element, index, array) {
    return isBoolean(element);
  });
}

/**
 * is a number array.
 */
function isNumberArray(arr) {
  return arr.every(function(element, index, array) {
    return isNumber(element);
  });
}

/**
 * is a number.
 */
function isNumber(value) {

  if (value) {
    if (typeof value === 'number') {
      return true;
    }
    return !isNaN(+value.toString());
  }

  return false;
}

/**
 * boolean type check.
 */
function isBoolean(value) {

  if (typeof(value) === "undefined") {
    return false;
  }

  if (typeof value === 'boolean') {
    return true;
  }

  let b = value.toString().trim().toLowerCase();

  return b === 'true' || b === 'false';
}

/**
 * date type check.
 */
// function isDateType(value) {
//   if (isNumber(value)) {
//     return false;
//   }
//   if (value) {
//     return moment(new Date(value), "YYYY-M-D", true).isValid() || moment(value, "YYYY-M-D H:m:s", true).isValid() || moment(value, "YYYY/M/D H:m:s", true).isValid() || moment(value, "YYYY/M/D", true).isValid();
//   }
//   return false;
// }

//fuck xlsx's bug
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
// var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
// function datenum(v, date1904) {
// 	var epoch = v.getTime();
// 	if(date1904) epoch -= 1462*24*60*60*1000;
// 	return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
// }

function numdate(v) {
  var out = new Date();
  out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
  return out;
}
//fuck over
<|endoftext|>