From d899b033f273fd79508ce7f2508556ecee11d510 Mon Sep 17 00:00:00 2001 From: mrmlnc Date: Fri, 3 Jan 2020 17:03:59 +0300 Subject: [PATCH] feat: Implementing "withFileTypes" option for fs.readdir method --- lib/binding.js | 33 +++++++++++++++++++++++++++--- test/lib/fs.readdir.spec.js | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/lib/binding.js b/lib/binding.js index bc4c6cb3..5d116b4e 100644 --- a/lib/binding.js +++ b/lib/binding.js @@ -12,6 +12,16 @@ const getPathParts = require('./filesystem').getPathParts; const bufferFrom = require('./buffer').from; const bufferAlloc = require('./buffer').alloc; +const MODE_TO_K_TYPE = { + [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; @@ -140,6 +150,16 @@ function wrapStatsCallback(callback) { } } +function getDirentType(mode) { + const ktype = MODE_TO_K_TYPE[mode & constants.S_IFMT]; + + if (ktype === undefined) { + return constants.UV_DIRENT_UNKNOWN; + } + + return ktype; +} + function notImplemented() { throw new Error('Method not implemented'); } @@ -914,9 +934,6 @@ Binding.prototype.readdir = function( } else if (arguments.length === 3) { callback = withFileTypes; } - if (withFileTypes === true) { - notImplemented(); - } markSyscall(ctx, 'scandir'); @@ -933,7 +950,17 @@ Binding.prototype.readdir = function( if (!(dir instanceof Directory)) { throw new FSError('ENOTDIR', dirpath); } + let list = dir.list(); + if (withFileTypes === true) { + const types = list.map(function(name) { + const stats = dir.getItem(name).getStats(); + + return getDirentType(stats.mode); + }); + list = [list, types]; + } + if (encoding === 'buffer') { list = list.map(function(item) { return bufferFrom(item); diff --git a/test/lib/fs.readdir.spec.js b/test/lib/fs.readdir.spec.js index eb9fa0a6..0091d346 100644 --- a/test/lib/fs.readdir.spec.js +++ b/test/lib/fs.readdir.spec.js @@ -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() { @@ -81,6 +82,45 @@ 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); + }); }); describe('fs.readdirSync(path)', function() {