Skip to content

Commit

Permalink
Merge pull request #287 from mrmlnc/readdir_with_file_types
Browse files Browse the repository at this point in the history
Implementing "withFileTypes" option for fs.readdir method
  • Loading branch information
tschaub committed Jan 7, 2020
2 parents ad93ac5 + ec9b267 commit 60cca44
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 3 deletions.
34 changes: 31 additions & 3 deletions lib/binding.js
Expand Up @@ -12,6 +12,16 @@ const getPathParts = require('./filesystem').getPathParts;
const bufferFrom = require('./buffer').from;
const bufferAlloc = require('./buffer').alloc;

const MODE_TO_KTYPE = {
[constants.S_IFREG]: constants.UV_DIRENT_FILE,
[constants.S_IFDIR]: constants.UV_DIRENT_DIR,
[constants.S_IFBLK]: constants.UV_DIRENT_BLOCK,
[constants.S_IFCHR]: constants.UV_DIRENT_CHAR,
[constants.S_IFLNK]: constants.UV_DIRENT_LINK,
[constants.S_IFIFO]: constants.UV_DIRENT_FIFO,
[constants.S_IFSOCK]: constants.UV_DIRENT_SOCKET
};

/** Workaround for optimizations in node 8+ */
const fsBinding = process.binding('fs');
const kUsePromises = fsBinding.kUsePromises;
Expand Down Expand Up @@ -140,6 +150,16 @@ function wrapStatsCallback(callback) {
}
}

function getDirentType(mode) {
const ktype = MODE_TO_KTYPE[mode & constants.S_IFMT];

if (ktype === undefined) {
return constants.UV_DIRENT_UNKNOWN;
}

return ktype;
}

function notImplemented() {
throw new Error('Method not implemented');
}
Expand Down Expand Up @@ -914,9 +934,6 @@ Binding.prototype.readdir = function(
} else if (arguments.length === 3) {
callback = withFileTypes;
}
if (withFileTypes === true) {
notImplemented();
}

markSyscall(ctx, 'scandir');

Expand All @@ -933,12 +950,23 @@ Binding.prototype.readdir = function(
if (!(dir instanceof Directory)) {
throw new FSError('ENOTDIR', dirpath);
}

let list = dir.list();
if (encoding === 'buffer') {
list = list.map(function(item) {
return bufferFrom(item);
});
}

if (withFileTypes === true) {
const types = list.map(function(name) {
const stats = dir.getItem(name).getStats();

return getDirentType(stats.mode);
});
list = [list, types];
}

return list;
});
};
Expand Down
90 changes: 90 additions & 0 deletions test/lib/fs.readdir.spec.js
Expand Up @@ -7,6 +7,7 @@ const path = require('path');

const assert = helper.assert;
const withPromise = helper.withPromise;
const inVersion = helper.inVersion;

describe('fs.readdir(path, callback)', function() {
beforeEach(function() {
Expand Down Expand Up @@ -81,6 +82,95 @@ describe('fs.readdir(path, callback)', function() {
}
);
});

inVersion('>=10.10').it('should support "withFileTypes" option', function(
done
) {
fs.readdir(
path.join('nested', 'sub', 'dir'),
{withFileTypes: true},
function(err, items) {
assert.isNull(err);
assert.isArray(items);
assert.deepEqual(items, [
{name: 'empty'},
{name: 'one.txt'},
{name: 'two.txt'}
]);
assert.ok(items[0].isDirectory());
assert.ok(items[1].isFile());
assert.ok(items[2].isFile());
done();
}
);
});

withPromise.it('should support "withFileTypes" option', function(done) {
fs.promises
.readdir(path.join('nested', 'sub', 'dir'), {withFileTypes: true})
.then(function(items) {
assert.isArray(items);
assert.deepEqual(items, [
{name: 'empty'},
{name: 'one.txt'},
{name: 'two.txt'}
]);
assert.ok(items[0].isDirectory());
assert.ok(items[1].isFile());
assert.ok(items[2].isFile());
done();
}, done);
});

inVersion('>=10.10').it(
'should support "withFileTypes" option with "encoding" option',
function(done) {
fs.readdir(
path.join('nested', 'sub', 'dir'),
{withFileTypes: true, encoding: 'buffer'},
function(err, items) {
assert.isNull(err);
assert.isArray(items);
items.forEach(function(item) {
assert.equal(Buffer.isBuffer(item.name), true);
});
const names = items.map(function(item) {
return item.name.toString();
});
assert.deepEqual(names, ['empty', 'one.txt', 'two.txt']);
assert.ok(items[0].isDirectory());
assert.ok(items[1].isFile());
assert.ok(items[2].isFile());
done();
}
);
}
);

withPromise.it(
'should support "withFileTypes" option with "encoding" option',
function(done) {
fs.promises
.readdir(path.join('nested', 'sub', 'dir'), {
withFileTypes: true,
encoding: 'buffer'
})
.then(function(items) {
assert.isArray(items);
items.forEach(function(item) {
assert.equal(Buffer.isBuffer(item.name), true);
});
const names = items.map(function(item) {
return item.name.toString();
});
assert.deepEqual(names, ['empty', 'one.txt', 'two.txt']);
assert.ok(items[0].isDirectory());
assert.ok(items[1].isFile());
assert.ok(items[2].isFile());
done();
});
}
);
});

describe('fs.readdirSync(path)', function() {
Expand Down

0 comments on commit 60cca44

Please sign in to comment.