Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add optionnable sorting capability #2

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ with help of [filer](https://github.com/filerjs/filer "Node-like file system for
```js
const readify = require('readify');

radify('/', (error, data) => {
// basic
readify('/', (error, data) => {
console.log(data);
// output
{
Expand All @@ -45,12 +46,14 @@ radify('/', (error, data) => {
size: '4.22kb',
date: '20.02.2016',
owner: 'coderaiser',
mode: 'rw- rw- r--'
mode: 'rw- rw- r--',
_raw: [object] // see bellow
}]
}
});

radify('/', 'raw', (error, data) => {
// raw output
readify('/', 'raw', (error, data) => {
console.log(data);
// output
{
Expand All @@ -64,6 +67,19 @@ radify('/', 'raw', (error, data) => {
}]
}
});

// sort output
// available sort option: name, size, owner, date
// available order option: asc, desc
readify('/', {sort: 'size', order: 'desc'}, (error, data) => {
console.log(data);
});

// all together
readify('/', {sort: 'size', order: 'desc', type: 'raw'}, (error, data) => {
console.log(data);
});

```

`browser` example:
Expand Down
87 changes: 71 additions & 16 deletions lib/readify.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,77 @@ const nicki = !WIN && !BROWSER && require('nicki/legacy');
const readdir = promisify(fs.readdir, fs);

/* sorting on Win and node v0.8.0 */
const sortFiles = sort((a, b) => {
return a.name > b.name ? 1 : -1;
const sortFiles = currify((attr, order, array) => {
switch (order) {
case 'desc':
// nothing
break;
case 'asc':
// nothing
break;
default:
order = 'asc';
}
var cmp;
switch (attr) {
case 'size':
cmp = (a, b) => (+a - +b);
break;
case 'date':
cmp = (a, b) => (a > b ? 1 : -1);
break;
case 'owner':
cmp = (a, b) => (a > b ? 1 : -1);
break;
case 'name':
cmp = (a, b) => a.localeCompare(b.attr);
break;
default:
attr = 'name';
cmp = (a, b) => a.localeCompare(b.attr);
}
return sort((a, b) => {
var res;
if (typeof a.raw !== 'undefined' && typeof b.raw !== 'undefined') {
res = cmp(a.raw[attr], b.raw[attr]);
} else {
res = cmp(a[attr], b[attr]);
}
if (order === 'desc') {
res = -res;
}
return res;
}, array);
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think sort-by can be used for sorting. It can simplify code a little bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not but no commit since 1 year ?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort-on uses dot-prop which is es2015 (and it requires to up major version of all modules which uses readify and drop support of old node.js versions). Maybe you know other modules which does the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort by seams very straightforward. We could fork it and write a backport with 'classic' attribute access.


const good = (f) => (...a) => f(null, ...a);

module.exports = readify;

function readify(path, type, fn) {
function readify(path, options, fn) {
if (!fn) {
fn = type;
type = '';
fn = options;
options = '';
}
if (typeof options !== 'object') {
options = {
type: options,
};
}
if (typeof options.sort === 'undefined') {
options.sort = '';
}
if (typeof options.order === 'undefined') {
options.order = '';
}
if (typeof options.type === 'undefined') {
options.type = '';
}

check(path, fn);

readdir(path)
.then(getAllStats(path, type))
.then(getAllStats(path, options))
.then(good(fn))
.catch(fn);
}
Expand All @@ -68,20 +121,20 @@ function check(path, callback) {
* @param path
* @param names
*/
function _getAllStats(path, type, names, callback) {
function _getAllStats(path, options, names, callback) {
const length = names.length;
const dir = format.addSlashToEnd(path);

if (!length)
return fillJSON(dir, [], type, callback);
return fillJSON(dir, [], options, callback);

const funcs = names.map((name) => {
return getStat(name, dir + name);
});

exec.parallel(funcs, (...args) => {
const files = args.slice(1);
fillJSON(dir, files, type, callback);
fillJSON(dir, files, options, callback);
});
}

Expand Down Expand Up @@ -111,15 +164,16 @@ function _parseAllStats(type, array) {
function parseStat(type, stat) {
const isDir = stat.isDirectory();
const size = isDir ? 'dir' : stat.size;

if (type === 'raw')
return {
const raw = {
name: stat.name,
size: size,
date: stat.mtime,
owner: stat.uid,
mode: stat.mode
};

if (type === 'raw')
return raw;

/* Переводим права доступа в 8-ричную систему */
const modeStr = Number(stat.mode).toString(8);
Expand All @@ -134,7 +188,8 @@ function parseStat(type, stat) {
size: format.size(size),
date: mtime,
owner: owner,
mode: mode && format.permissions.symbolic(mode)
mode: mode && format.permissions.symbolic(mode),
raw: raw
};
}

Expand All @@ -143,16 +198,16 @@ function parseStat(type, stat) {
*
* @param params - { files, stats, path }
*/
function fillJSON(path, stats, type, callback) {
const processFiles = squad(changeOrder, sortFiles, parseAllStats(type));
function fillJSON(path, stats, options, callback) {
const processFiles = squad(changeOrder, sortFiles(options.sort, options.order), parseAllStats(options.type));
const json = {
path: '',
files: processFiles(stats)
};

json.path = format.addSlashToEnd(path);

if (type === 'raw')
if (options.type === 'raw')
return callback(null, json);

changeUIDToName(json, (error, files) => {
Expand Down
1 change: 1 addition & 0 deletions test/dir/1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
111
1 change: 1 addition & 0 deletions test/dir/2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2
1 change: 1 addition & 0 deletions test/dir/3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
33
141 changes: 94 additions & 47 deletions test/readify.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ test('result: should be sorted by name folders then files', (t) => {
});
});

test('readify: result: no owner', (t) => {
test('readify: result', (t) => {
const update = () => {
delete require.cache[require.resolve('..')];
readify = require('..');
Expand Down Expand Up @@ -107,51 +107,12 @@ test('readify: result: no owner', (t) => {
update();

readify('.', (error, result) => {
delete result.files[0].owner;
t.deepEqual(result, expected, 'should get raw values');

fs.readdir = readdir;
fs.stat = stat;

update();

t.end();
});
});

test('readify: result: owner', (t) => {
const update = () => {
delete require.cache[require.resolve('..')];
readify = require('..');
};

const {readdir, stat} = fs;

const name = 'hello.txt';
const mode = 16893;
const size = 1024;
const mtime = new Date('2016-11-23T14:36:46.311Z');
const uid = 2;

fs.readdir = (dir, fn) => {
fn(null, [name]);
};

fs.stat = (name, fn) => {
fn(null, {
isDirectory: noop,
name,
mode,
size,
mtime,
uid
result.files = result.files.map(function(file) {
delete file.raw;
delete file.owner;
return file;
});
};

update();

readify('.', (error, result) => {
t.ok(result.files[0].owner, 'should contain owner');
t.deepEqual(result, expected, 'should get raw values');

fs.readdir = readdir;
fs.stat = stat;
Expand Down Expand Up @@ -276,7 +237,7 @@ test('result: files should have fields name, size, date, owner, mode', (t) => {
length = files.length,
check = () =>
files.filter((file) =>
Object.keys(file).join(':') === 'name:size:date:owner:mode'
Object.keys(file).join(':') === 'name:size:date:owner:mode:raw'
).length;

t.notOk(error, 'no error');
Expand Down Expand Up @@ -356,14 +317,100 @@ test('readify stat: error', (t) => {
const dir = path.resolve(__dirname, '..', 'dist');
readify(dir, (error, data) => {
t.notOk(error, 'no error when stat error');

data.files = data.files.map(function(file) {
delete file.raw;
return file;
});
t.deepEqual(data.files, files, 'size, date, owner, mode should be empty');

fs.stat = stat;
t.end();
});
});

test('readify sort: name asc', (t) => {
const files = [
'1.txt',
'2.txt',
'3.txt'
];

readify('./test/dir', {sort: 'name'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

test('readify sort: name desc', (t) => {
const files = [
'3.txt',
'2.txt',
'1.txt'
];

readify('./test/dir', {sort: 'name', order: 'desc'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

test('readify sort: size asc', (t) => {
const files = [
'2.txt',
'3.txt',
'1.txt'
];

readify('./test/dir', {sort: 'size', order: 'asc'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

test('readify sort: size asc raw', (t) => {
const files = [
'2.txt',
'3.txt',
'1.txt'
];

readify('./test/dir', {sort: 'size', type: 'raw'}, (error, data) => {
t.notOk(error, 'no error');
data.files = data.files.map(function(file) {
return file.name;
});
t.deepEqual(data.files, files, 'correct order');
t.end();
});
});

// no comment
test('readify sort: owner', (t) => {
readify('./test/dir', {sort: 'owner'}, (error) => {
t.notOk(error, 'no error');
t.end();
});
});

test('readify sort: date', (t) => {
readify('./test/dir', {sort: 'date'}, (error) => {
t.notOk(error, 'no error');
t.end();
});
});

test('browser: filer', (t) => {
const Filer = {
FileSystem: sinon.stub()
Expand Down