sort.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. var common = require('./common');
  2. var fs = require('fs');
  3. common.register('sort', _sort, {
  4. canReceivePipe: true,
  5. cmdOptions: {
  6. 'r': 'reverse',
  7. 'n': 'numerical',
  8. },
  9. });
  10. // parse out the number prefix of a line
  11. function parseNumber(str) {
  12. var match = str.match(/^\s*(\d*)\s*(.*)$/);
  13. return { num: Number(match[1]), value: match[2] };
  14. }
  15. // compare two strings case-insensitively, but examine case for strings that are
  16. // case-insensitive equivalent
  17. function unixCmp(a, b) {
  18. var aLower = a.toLowerCase();
  19. var bLower = b.toLowerCase();
  20. return (aLower === bLower ?
  21. -1 * a.localeCompare(b) : // unix sort treats case opposite how javascript does
  22. aLower.localeCompare(bLower));
  23. }
  24. // compare two strings in the fashion that unix sort's -n option works
  25. function numericalCmp(a, b) {
  26. var objA = parseNumber(a);
  27. var objB = parseNumber(b);
  28. if (objA.hasOwnProperty('num') && objB.hasOwnProperty('num')) {
  29. return ((objA.num !== objB.num) ?
  30. (objA.num - objB.num) :
  31. unixCmp(objA.value, objB.value));
  32. } else {
  33. return unixCmp(objA.value, objB.value);
  34. }
  35. }
  36. //@
  37. //@ ### sort([options,] file [, file ...])
  38. //@ ### sort([options,] file_array)
  39. //@
  40. //@ Available options:
  41. //@
  42. //@ + `-r`: Reverse the results
  43. //@ + `-n`: Compare according to numerical value
  44. //@
  45. //@ Examples:
  46. //@
  47. //@ ```javascript
  48. //@ sort('foo.txt', 'bar.txt');
  49. //@ sort('-r', 'foo.txt');
  50. //@ ```
  51. //@
  52. //@ Return the contents of the `file`s, sorted line-by-line. Sorting multiple
  53. //@ files mixes their content (just as unix `sort` does).
  54. function _sort(options, files) {
  55. // Check if this is coming from a pipe
  56. var pipe = common.readFromPipe();
  57. if (!files && !pipe) common.error('no files given');
  58. files = [].slice.call(arguments, 1);
  59. if (pipe) {
  60. files.unshift('-');
  61. }
  62. var lines = files.reduce(function (accum, file) {
  63. if (file !== '-') {
  64. if (!fs.existsSync(file)) {
  65. common.error('no such file or directory: ' + file, { continue: true });
  66. return accum;
  67. } else if (common.statFollowLinks(file).isDirectory()) {
  68. common.error('read failed: ' + file + ': Is a directory', {
  69. continue: true,
  70. });
  71. return accum;
  72. }
  73. }
  74. var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8');
  75. return accum.concat(contents.trimRight().split('\n'));
  76. }, []);
  77. var sorted = lines.sort(options.numerical ? numericalCmp : unixCmp);
  78. if (options.reverse) {
  79. sorted = sorted.reverse();
  80. }
  81. return sorted.join('\n') + '\n';
  82. }
  83. module.exports = _sort;