UNPKG

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