From 503fb6be9689a0a3369fd075f5e6c1ea96996813 Mon Sep 17 00:00:00 2001 From: segayuu Date: Mon, 4 Sep 2017 13:22:33 +0900 Subject: [PATCH 1/4] added npm module "hexo-fs". --- types/hexo-fs/hexo-fs-tests.ts | 991 +++++++++++++++++++++++++++++++++ types/hexo-fs/index.d.ts | 295 ++++++++++ types/hexo-fs/tsconfig.json | 22 + types/hexo-fs/tslint.json | 3 + 4 files changed, 1311 insertions(+) create mode 100644 types/hexo-fs/hexo-fs-tests.ts create mode 100644 types/hexo-fs/index.d.ts create mode 100644 types/hexo-fs/tsconfig.json create mode 100644 types/hexo-fs/tslint.json diff --git a/types/hexo-fs/hexo-fs-tests.ts b/types/hexo-fs/hexo-fs-tests.ts new file mode 100644 index 0000000000..71e6d99e1b --- /dev/null +++ b/types/hexo-fs/hexo-fs-tests.ts @@ -0,0 +1,991 @@ +import fs = require('hexo-fs'); +import path = require('path'); +import mocha = require('mocha'); +import chai = require('chai'); +import Promise = require('bluebird'); + +const should = chai.should(); +const { join } = path; + +function createDummyFolder(path: string) { + return Promise.all([ + // Normal files in a hidden folder + fs.writeFile(join(path, '.hidden', 'a.txt'), 'a'), + fs.writeFile(join(path, '.hidden', 'b.js'), 'b'), + // Normal folder in a hidden folder + fs.writeFile(join(path, '.hidden', 'c', 'd'), 'd'), + // Top-class files + fs.writeFile(join(path, 'e.txt'), 'e'), + fs.writeFile(join(path, 'f.js'), 'f'), + // A hidden file + fs.writeFile(join(path, '.g'), 'g'), + // Files in a normal folder + fs.writeFile(join(path, 'folder', 'h.txt'), 'h'), + fs.writeFile(join(path, 'folder', 'i.js'), 'i'), + // A hidden files in a normal folder + fs.writeFile(join(path, 'folder', '.j'), 'j') + ]); +} + +const tmpDir = join(__dirname, 'fs_tmp'); + +before(() => fs.mkdirs(tmpDir)); + +after((done) => { + fs.rmdir(tmpDir); + done(); +}); + +it('exists()', () => { + return fs.exists(tmpDir).then((exist) => { + exist.should.be.true; + }); +}); + +it('exists() - callback', (callback) => { + fs.exists(tmpDir, (exist) => { + exist.should.be.true; + callback(); + }); +}); + +it('mkdirs()', () => { + const target = join(tmpDir, 'a', 'b', 'c'); + + return fs.mkdirs(target).then(() => { + return fs.exists(target); + }).then((exist) => { + exist.should.be.true; + return fs.rmdir(join(tmpDir, 'a')); + }); +}); + +it('mkdirs() - callback', (callback) => { + const target = join(tmpDir, 'a', 'b', 'c'); + + fs.mkdirs(target, (err) => { + should.not.exist(err); + + fs.exists(target, (exist) => { + exist.should.be.true; + fs.rmdir(join(tmpDir, 'a'), callback); + }); + }); +}); + +it('mkdirsSync()', () => { + const target = join(tmpDir, 'a', 'b', 'c'); + + fs.mkdirsSync(target); + + return fs.exists(target).then((exist) => { + exist.should.be.true; + return fs.rmdir(join(tmpDir, 'a')); + }); +}); + +it('writeFile()', () => { + const target = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + + return fs.writeFile(target, body).then(() => { + return fs.readFile(target); + }).then((content) => { + content.should.eql(body); + return fs.rmdir(join(tmpDir, 'a')); + }); +}); + +it('writeFile() - callback', (callback) => { + const target = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + + fs.writeFile(target, body, (err) => { + should.not.exist(err); + + fs.readFile(target, (_, content) => { + content!.should.eql(body); + fs.rmdir(join(tmpDir, 'a'), callback); + }); + }); +}); + +it('writeFileSync()', () => { + const target = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + + fs.writeFileSync(target, body); + + return fs.readFile(target).then((content) => { + content.should.eql(body); + return fs.rmdir(join(tmpDir, 'a')); + }); +}); + +it('appendFile()', () => { + const target = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + const body2 = 'bar'; + + return fs.writeFile(target, body).then(() => { + return fs.appendFile(target, body2); + }).then(() => { + return fs.readFile(target); + }).then((content) => { + content.should.eql(body + body2); + return fs.rmdir(join(tmpDir, 'a')); + }); +}); + +it('appendFile() - callback', (callback) => { + const target = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + const body2 = 'bar'; + + fs.writeFile(target, body, () => { + fs.appendFile(target, body2, (err) => { + should.not.exist(err); + + fs.readFile(target, (_, content) => { + content!.should.eql(body + body2); + fs.rmdir(join(tmpDir, 'a'), callback); + }); + }); + }); +}); + +it('appendFileSync()', () => { + const target = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + const body2 = 'bar'; + + return fs.writeFile(target, body).then(() => { + fs.appendFileSync(target, body2); + return fs.readFile(target); + }).then((content) => { + content.should.eql(body + body2); + return fs.rmdir(join(tmpDir, 'a')); + }); +}); + +it('copyFile()', () => { + const src = join(tmpDir, 'test.txt'); + const dest = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + + return fs.writeFile(src, body).then(() => { + return fs.copyFile(src, dest); + }).then(() => { + return fs.readFile(dest); + }).then((content) => { + content.should.eql(body); + + return Promise.all([ + fs.unlink(src), + fs.rmdir(join(tmpDir, 'a')) + ]); + }); +}); + +it('copyFile() - callback', (callback) => { + const src = join(tmpDir, 'test.txt'); + const dest = join(tmpDir, 'a', 'b', 'test.txt'); + const body = 'foo'; + + fs.writeFile(src, body, (err) => { + if (err) return callback(err); + + fs.copyFile(src, dest, (err) => { + if (err) return callback(err); + + fs.readFile(dest, (err, content) => { + if (err) return callback(err); + content!.should.eql(body); + + Promise.all([ + fs.unlink(src), + fs.rmdir(join(tmpDir, 'a')) + ]).asCallback(callback); + }); + }); + }); +}); + +it('copyDir()', () => { + const src = join(tmpDir, 'a'); + const dest = join(tmpDir, 'b'); + + return createDummyFolder(src).then(() => { + return fs.copyDir(src, dest); + }).then((files) => { + files.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + return Promise.all([ + fs.readFile(join(dest, 'e.txt')), + fs.readFile(join(dest, 'f.js')), + fs.readFile(join(dest, 'folder', 'h.txt')), + fs.readFile(join(dest, 'folder', 'i.js')) + ]); + }).then((result) => { + result.should.eql(['e', 'f', 'h', 'i']); + }).then(() => { + return Promise.all([ + fs.rmdir(src), + fs.rmdir(dest) + ]); + }); +}); + +it('copyDir() - callback', (callback) => { + const src = join(tmpDir, 'a'); + const dest = join(tmpDir, 'b'); + + createDummyFolder(src).then(() => { + fs.copyDir(src, dest, (err, files) => { + should.not.exist(err); + files!.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + Promise.all([ + fs.readFile(join(dest, 'e.txt')), + fs.readFile(join(dest, 'f.js')), + fs.readFile(join(dest, 'folder', 'h.txt')), + fs.readFile(join(dest, 'folder', 'i.js')) + ]).then((result) => { + result.should.eql(['e', 'f', 'h', 'i']); + }).then(() => { + return Promise.all([ + fs.rmdir(src), + fs.rmdir(dest) + ]); + }).asCallback(callback); + }); + }); +}); + +it('copyDir() - ignoreHidden off', () => { + const src = join(tmpDir, 'a'); + const dest = join(tmpDir, 'b'); + + return createDummyFolder(src).then(() => { + return fs.copyDir(src, dest, { ignoreHidden: false }); + }).then((files) => { + files.should.have.members([ + join('.hidden', 'a.txt'), + join('.hidden', 'b.js'), + join('.hidden', 'c', 'd'), + 'e.txt', + 'f.js', + '.g', + join('folder', 'h.txt'), + join('folder', 'i.js'), + join('folder', '.j') + ]); + + return Promise.all([ + fs.readFile(join(dest, '.hidden', 'a.txt')), + fs.readFile(join(dest, '.hidden', 'b.js')), + fs.readFile(join(dest, '.hidden', 'c', 'd')), + fs.readFile(join(dest, 'e.txt')), + fs.readFile(join(dest, 'f.js')), + fs.readFile(join(dest, '.g')), + fs.readFile(join(dest, 'folder', 'h.txt')), + fs.readFile(join(dest, 'folder', 'i.js')), + fs.readFile(join(dest, 'folder', '.j')) + ]); + }).then((result) => { + result.should.eql(['a', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j']); + }).then(() => { + return Promise.all([ + fs.rmdir(src), + fs.rmdir(dest) + ]); + }); +}); + +it('copyDir() - ignorePattern', () => { + const src = join(tmpDir, 'a'); + const dest = join(tmpDir, 'b'); + + return createDummyFolder(src).then(() => { + return fs.copyDir(src, dest, { ignorePattern: /\.js/ }); + }).then((files) => { + files.should.have.members(['e.txt', join('folder', 'h.txt')]); + + return Promise.all([ + fs.readFile(join(dest, 'e.txt')), + fs.readFile(join(dest, 'folder', 'h.txt')) + ]); + }).then((result) => { + result.should.eql(['e', 'h']); + }).then(() => { + return Promise.all([ + fs.rmdir(src), + fs.rmdir(dest) + ]); + }); +}); + +it('listDir()', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.listDir(target); + }).then((files) => { + files.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + return fs.rmdir(target); + }); +}); + +it('listDir() - callback', (callback) => { + const target = join(tmpDir, 'test'); + + createDummyFolder(target).then(() => { + fs.listDir(target, (err, files) => { + if (err) return callback(err); + + files!.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + fs.rmdir(target, callback); + }); + }); +}); + +it('listDir() - ignoreHidden off', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.listDir(target, { ignoreHidden: false }); + }).then((files) => { + files.should.have.members([ + join('.hidden', 'a.txt'), + join('.hidden', 'b.js'), + join('.hidden', 'c', 'd'), + 'e.txt', + 'f.js', + '.g', + join('folder', 'h.txt'), + join('folder', 'i.js'), + join('folder', '.j') + ]); + + return fs.rmdir(target); + }); +}); + +it('listDir() - ignorePattern', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.listDir(target, { ignorePattern: /\.js/ }); + }).then((files) => { + files.should.have.members(['e.txt', join('folder', 'h.txt')]); + return fs.rmdir(target); + }); +}); + +it('listDirSync()', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + const files = fs.listDirSync(target); + files.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + return fs.rmdir(target); + }); +}); + +it('listDirSync() - ignoreHidden off', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + const files = fs.listDirSync(target, { ignoreHidden: false }); + files.should.have.members([ + join('.hidden', 'a.txt'), + join('.hidden', 'b.js'), + join('.hidden', 'c', 'd'), + 'e.txt', + 'f.js', + '.g', + join('folder', 'h.txt'), + join('folder', 'i.js'), + join('folder', '.j') + ]); + + return fs.rmdir(target); + }); +}); + +it('listDirSync() - ignorePattern', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + const files = fs.listDirSync(target, { ignorePattern: /\.js/ }); + files.should.have.members(['e.txt', join('folder', 'h.txt')]); + return fs.rmdir(target); + }); +}); + +it('readFile()', () => { + const target = join(tmpDir, 'test.txt'); + const body = 'test'; + + return fs.writeFile(target, body).then(() => { + return fs.readFile(target); + }).then((content) => { + content.should.eql(body); + return fs.unlink(target); + }); +}); + +it('readFile() - callback', (callback) => { + const target = join(tmpDir, 'test.txt'); + const body = 'test'; + + fs.writeFile(target, body, (err) => { + if (err) return callback(err); + + fs.readFile(target, (err, content) => { + if (err) return callback(err); + + content!.should.eql(body); + + fs.unlink(target).asCallback(callback); + }); + }); +}); + +it('readFile() - escape BOM', () => { + const target = join(tmpDir, 'test.txt'); + const body = '\ufefffoo'; + + return fs.writeFile(target, body).then(() => { + return fs.readFile(target); + }).then((content) => { + content.should.eql('foo'); + return fs.unlink(target); + }); +}); + +it('readFile() - escape Windows line ending', () => { + const target = join(tmpDir, 'test.txt'); + const body = 'foo\r\nbar'; + + return fs.writeFile(target, body).then(() => { + return fs.readFile(target); + }).then((content) => { + content.should.eql('foo\nbar'); + return fs.unlink(target); + }); +}); + +it('readFileSync()', () => { + const target = join(tmpDir, 'test.txt'); + const body = 'test'; + + return fs.writeFile(target, body).then(() => { + fs.readFileSync(target).should.eql(body); + return fs.unlink(target); + }); +}); + +it('readFileSync() - escape BOM', () => { + const target = join(tmpDir, 'test.txt'); + const body = '\ufefffoo'; + + return fs.writeFile(target, body).then(() => { + fs.readFileSync(target).should.eql('foo'); + return fs.unlink(target); + }); +}); + +it('readFileSync() - escape Windows line ending', () => { + const target = join(tmpDir, 'test.txt'); + const body = 'foo\r\nbar'; + + return fs.writeFile(target, body).then(() => { + fs.readFileSync(target).should.eql('foo\nbar'); + return fs.unlink(target); + }); +}); + +it('unlink()', () => { + const target = join(tmpDir, 'test-unlink'); + + return fs.writeFile(target, '').then(() => { + return fs.exists(target); + }).then((exist) => { + exist.should.eql(true); + return fs.unlink(target); + }).then(() => { + return fs.exists(target); + }).then((exist) => { + exist.should.eql(false); + }); +}); + +it('emptyDir()', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.emptyDir(target); + }).then>((files) => { + files.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + return [ + [join(target, '.hidden', 'a.txt'), true], + [join(target, '.hidden', 'b.js'), true], + [join(target, '.hidden', 'c', 'd'), true], + [join(target, 'e.txt'), false], + [join(target, 'f.js'), false], + [join(target, '.g'), true], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), false], + [join(target, 'folder', '.j'), true] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('emptyDir() - callback', (callback) => { + const target = join(tmpDir, 'test'); + + createDummyFolder(target).then(() => { + fs.emptyDir(target, (err, files) => { + if (err) return callback(err); + + files!.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + Promise.map<[string, boolean], void>([ + [join(target, '.hidden', 'a.txt'), true], + [join(target, '.hidden', 'b.js'), true], + [join(target, '.hidden', 'c', 'd'), true], + [join(target, 'e.txt'), false], + [join(target, 'f.js'), false], + [join(target, '.g'), true], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), false], + [join(target, 'folder', '.j'), true] + ], (data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }).asCallback(callback); + }); + }); +}); + +it('emptyDir() - ignoreHidden off', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.emptyDir(target, { ignoreHidden: false }); + }).then>((files) => { + files.should.have.members([ + join('.hidden', 'a.txt'), + join('.hidden', 'b.js'), + join('.hidden', 'c', 'd'), + 'e.txt', + 'f.js', + '.g', + join('folder', 'h.txt'), + join('folder', 'i.js'), + join('folder', '.j') + ]); + + return [ + [join(target, '.hidden', 'a.txt'), false], + [join(target, '.hidden', 'b.js'), false], + [join(target, '.hidden', 'c', 'd'), false], + [join(target, 'e.txt'), false], + [join(target, 'f.js'), false], + [join(target, '.g'), false], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), false], + [join(target, 'folder', '.j'), false] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('emptyDir() - ignorePattern', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.emptyDir(target, { ignorePattern: /\.js/ }); + }).then>((files) => { + files.should.have.members(['e.txt', join('folder', 'h.txt')]); + + return [ + [join(target, '.hidden', 'a.txt'), true], + [join(target, '.hidden', 'b.js'), true], + [join(target, '.hidden', 'c', 'd'), true], + [join(target, 'e.txt'), false], + [join(target, 'f.js'), true], + [join(target, '.g'), true], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), true], + [join(target, 'folder', '.j'), true] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('emptyDir() - exclude', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.emptyDir(target, { exclude: ['e.txt', join('folder', 'i.js')] }); + }).then>((files) => { + files.should.have.members(['f.js', join('folder', 'h.txt')]); + + return [ + [join(target, '.hidden', 'a.txt'), true], + [join(target, '.hidden', 'b.js'), true], + [join(target, '.hidden', 'c', 'd'), true], + [join(target, 'e.txt'), true], + [join(target, 'f.js'), false], + [join(target, '.g'), true], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), true], + [join(target, 'folder', '.j'), true] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('emptyDirSync()', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then>(() => { + const files = fs.emptyDirSync(target); + files.should.have.members([ + 'e.txt', + 'f.js', + join('folder', 'h.txt'), + join('folder', 'i.js') + ]); + + return [ + [join(target, '.hidden', 'a.txt'), true], + [join(target, '.hidden', 'b.js'), true], + [join(target, '.hidden', 'c', 'd'), true], + [join(target, 'e.txt'), false], + [join(target, 'f.js'), false], + [join(target, '.g'), true], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), false], + [join(target, 'folder', '.j'), true] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('emptyDirSync() - ignoreHidden off', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then>(() => { + const files = fs.emptyDirSync(target, { ignoreHidden: false }); + files.should.have.members([ + join('.hidden', 'a.txt'), + join('.hidden', 'b.js'), + join('.hidden', 'c', 'd'), + 'e.txt', + 'f.js', + '.g', + join('folder', 'h.txt'), + join('folder', 'i.js'), + join('folder', '.j') + ]); + + return [ + [join(target, '.hidden', 'a.txt'), false], + [join(target, '.hidden', 'b.js'), false], + [join(target, '.hidden', 'c', 'd'), false], + [join(target, 'e.txt'), false], + [join(target, 'f.js'), false], + [join(target, '.g'), false], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), false], + [join(target, 'folder', '.j'), false] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('emptyDirSync() - ignorePattern', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then>(() => { + const files = fs.emptyDirSync(target, { ignorePattern: /\.js/ }); + files.should.have.members(['e.txt', join('folder', 'h.txt')]); + + return [ + [join(target, '.hidden', 'a.txt'), true], + [join(target, '.hidden', 'b.js'), true], + [join(target, '.hidden', 'c', 'd'), true], + [join(target, 'e.txt'), false], + [join(target, 'f.js'), true], + [join(target, '.g'), true], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), true], + [join(target, 'folder', '.j'), true] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('emptyDirSync() - exclude', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then>(() => { + const files = fs.emptyDirSync(target, { exclude: ['e.txt', join('folder', 'i.js')] }); + files.should.have.members(['f.js', join('folder', 'h.txt')]); + + return [ + [join(target, '.hidden', 'a.txt'), true], + [join(target, '.hidden', 'b.js'), true], + [join(target, '.hidden', 'c', 'd'), true], + [join(target, 'e.txt'), true], + [join(target, 'f.js'), false], + [join(target, '.g'), true], + [join(target, 'folder', 'h.txt'), false], + [join(target, 'folder', 'i.js'), true], + [join(target, 'folder', '.j'), true] + ]; + }).map((data: [string, boolean]) => { + return fs.exists(data[0]).then((exist) => { + exist.should.eql(data[1]); + }); + }).then(() => { + return fs.rmdir(target); + }); +}); + +it('rmdir()', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + return fs.rmdir(target); + }).then(() => { + return fs.exists(target); + }).then((exist) => { + exist.should.be.false; + }); +}); + +it('rmdir() - callback', (callback) => { + const target = join(tmpDir, 'test'); + + createDummyFolder(target).then(() => { + fs.rmdir(target, (err) => { + should.not.exist(err); + + fs.exists(target, (exist) => { + exist.should.be.false; + callback(); + }); + }); + }); +}); + +it('rmdirSync()', () => { + const target = join(tmpDir, 'test'); + + return createDummyFolder(target).then(() => { + fs.rmdirSync(target); + return fs.exists(target); + }).then((exist) => { + exist.should.be.false; + }); +}); + +import { FSWatcher } from 'chokidar'; + +it('watch()', () => { + let watcher: FSWatcher; + + return fs.watch(tmpDir).then((watcher_) => { + watcher = watcher_; + + return new Promise((resolve, reject) => { + const path = join(tmpDir, 'test.txt'); + + watcher.on('add', (path_) => { + path_.should.eql(path); + resolve(); + }); + + fs.writeFile(path, 'test').catch(reject); + }); + }).finally(() => { + if (watcher) watcher.close(); + }); +}); + +it('ensurePath() - file exists', () => { + const target = join(tmpDir, 'test'); + + return Promise.all([ + fs.writeFile(join(target, 'foo.txt'), ''), + fs.writeFile(join(target, 'foo-1.txt'), ''), + fs.writeFile(join(target, 'foo-2.md'), ''), + fs.writeFile(join(target, 'bar.txt'), '') + ]).then(() => { + return fs.ensurePath(join(target, 'foo.txt')); + }).then((path) => { + path.should.eql(join(target, 'foo-2.txt')); + return fs.rmdir(target); + }); +}); + +it('ensurePath() - file not exist', () => { + const target = join(tmpDir, 'foo.txt'); + + return fs.ensurePath(target).then((path) => { + path.should.eql(target); + }); +}); + +it('ensurePath() - callback', (callback) => { + const target = join(tmpDir, 'test'); + + Promise.all([ + fs.writeFile(join(target, 'foo.txt'), ''), + fs.writeFile(join(target, 'foo-1.txt'), ''), + fs.writeFile(join(target, 'foo-2.md'), ''), + fs.writeFile(join(target, 'bar.txt'), '') + ]).then(() => { + fs.ensurePath(join(target, 'foo.txt'), (err, path) => { + should.not.exist(err); + path!.should.eql(join(target, 'foo-2.txt')); + fs.rmdir(target, callback); + }); + }); +}); + +it('ensurePathSync() - file exists', () => { + const target = join(tmpDir, 'test'); + + return Promise.all([ + fs.writeFile(join(target, 'foo.txt'), ''), + fs.writeFile(join(target, 'foo-1.txt'), ''), + fs.writeFile(join(target, 'foo-2.md'), ''), + fs.writeFile(join(target, 'bar.txt'), '') + ]).then(() => { + const path = fs.ensurePathSync(join(target, 'foo.txt')); + path.should.eql(join(target, 'foo-2.txt')); + + return fs.rmdir(target); + }); +}); + +it('ensurePathSync() - file not exist', () => { + const target = join(tmpDir, 'foo.txt'); + const path = fs.ensurePathSync(target); + + path.should.eql(target); +}); + +it('ensureWriteStream()', () => { + const target = join(tmpDir, 'foo', 'bar.txt'); + + return fs.ensureWriteStream(target).then((stream) => { + stream.path.should.eql(target); + stream.on('finish', () => { + return fs.unlink(target); + }); + }); +}); + +it('ensureWriteStream() - callback', (callback) => { + const target = join(tmpDir, 'foo', 'bar.txt'); + + fs.ensureWriteStream(target, (err, stream) => { + should.not.exist(err); + stream!.path.should.eql(target); + callback(); + }); +}); + +it('ensureWriteStreamSync()', () => { + const target = join(tmpDir, 'foo', 'bar.txt'); + const stream = fs.ensureWriteStreamSync(target); + + stream.path.should.eql(target); + stream.on('finish', () => { + return fs.rmdir(path.dirname(target)); + }); +}); diff --git a/types/hexo-fs/index.d.ts b/types/hexo-fs/index.d.ts new file mode 100644 index 0000000000..eae1e79c06 --- /dev/null +++ b/types/hexo-fs/index.d.ts @@ -0,0 +1,295 @@ +// Type definitions for hexo-fs 0.2 +// Project: https://github.com/hexojs/hexo-fs +// Definitions by: Sega Yuu +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +/// + +import Promise = require('bluebird'); +import { + PathLike, + Stats, + ReadStream, + WriteStream, + // chmod, + chmodSync, + // fchmod, + fchmodSync, + // lchmod, + lchmodSync, + // chown, + chownSync, + // fchown, + fchownSync, + // lchown, + lchownSync, + // close, + closeSync, + createReadStream, + createWriteStream, + // fsync, + fsyncSync, + // link, + linkSync, + // mkdir, + mkdirSync, + // open, + openSync, + // symlink, + symlinkSync, + // read, + readSync, + // readdir, + readdirSync, + // readlink, + readlinkSync, + // realpath, + realpathSync, + // rename, + renameSync, + // stat, + statSync, + // fstat, + fstatSync, + // lstat, + lstatSync, + // truncate, + truncateSync, + // ftruncate, + ftruncateSync, + // unlink, + unlinkSync, + // utimes, + utimesSync, + // futimes, + futimesSync, + watchFile, + unwatchFile, + // write, + writeSync + } from 'graceful-fs'; + +export interface DirectoryOptions { + ignoreHidden?: boolean; + ignorePattern?: RegExp; +} + +export interface AppendFileOptions { + encoding?: string | null; + mode?: string | number; + flag?: string; +} + +// access +export let F_OK: number | undefined; +export let R_OK: number | undefined; +export let W_OK: number | undefined; +export let X_OK: number | undefined; + +export let access: ((path: PathLike, mode?: number) => Promise) | undefined; // promisify +export let accessSync: ((path: PathLike, mode?: number) => void) | undefined; // promisify + +// appendFile +export function appendFile(path: string, data: any, callback?: (err: any) => void): Promise; +export function appendFile(path: string, data: any, options: string | AppendFileOptions, callback?: (err: any) => void): Promise; +export function appendFileSync(path: string, data: any, options?: string | AppendFileOptions): void; + +// chmod +export function chmod(path: PathLike, mode: string | number): Promise; // promisify +export function fchmod(fd: number, mode: string | number): Promise; // promisify +export function lchmod(path: PathLike, mode: string | number): Promise; // promisify +export { chmodSync, fchmodSync, lchmodSync }; + +// chown +export function chown(path: PathLike, uid: number, gid: number): Promise; // promisify +export function fchown(fd: number, uid: number, gid: number): Promise; // promisify +export function lchown(path: PathLike, uid: number, gid: number): Promise; // promisify +export { chownSync, fchownSync, lchownSync }; + +// close +export function close(fd: number): Promise; // promisify +export { closeSync }; + +// copy +export function copyDir(src: string, dest: string, callback?: (err: any, value?: string[]) => void): Promise; +export function copyDir(src: string, dest: string, options?: DirectoryOptions, callback?: (err: any, value?: string[]) => void): Promise; +export function copyFile(src: PathLike, dest: string, callback?: (err: any) => void): Promise; + +// createStream +export { createReadStream, createWriteStream }; + +// emptyDir +export function emptyDir(path: string, callback?: (err: any, value?: string | string[]) => void): Promise; +export function emptyDir( + path: string, + options?: DirectoryOptions & { exclude?: string[] }, + callback?: (err: any, value?: string | string[]) => void +): Promise; +export function emptyDirSync(path: string, options?: DirectoryOptions & { exclude?: string[] }, parent?: string): string | string[]; + +// ensurePath +export function ensurePath(path: string, callback?: (err: any, value?: string) => void): Promise; +export function ensurePathSync(path: string): string; + +// ensureWriteStream +export function ensureWriteStream(path: string, callback?: (err: any, value?: WriteStream) => void): Promise; +export function ensureWriteStream( + path: string, + options?: string | { + flags?: string; + defaultEncoding?: string; + fd?: number; + mode?: number; + autoClose?: boolean; + start?: number; + }, + callback?: (err: any, value?: WriteStream) => void +): Promise; +export function ensureWriteStreamSync(path: string, options?: string | { + flags?: string; + defaultEncoding?: string; + fd?: number; + mode?: number; + autoClose?: boolean; + start?: number; +}): WriteStream; + +// exists +export function exists(path: PathLike, callback?: (exist: boolean) => void): Promise; +export function existsSync(path: PathLike): boolean; + +// fsync +export function fsync(fd: number): Promise; // promisify +export { fsyncSync }; + +// link +export function link(existingPath: PathLike, newPath: PathLike): Promise; // promisify +export { linkSync }; + +// listDir +export function listDir(path: string, callback?: (err: any, value?: string[]) => void): Promise; +export function listDir(path: string, options?: DirectoryOptions, callback?: (err: any, value?: string[]) => void): Promise; +export function listDirSync(path: string, options?: DirectoryOptions, parent?: string): string | string[]; + +// mkdir +export function mkdir(path: PathLike, mode?: string | number): Promise; // promisify +export { mkdirSync }; + +// mkdirs +export function mkdirs(path: PathLike, callback?: (err: any) => void): Promise; +export function mkdirsSync(path: string): void; + +// open +export function open(path: PathLike, flags: string | number, mode?: string | number | null): Promise; // promisify +export { openSync }; + +// symlink +export function symlink(target: PathLike, path: PathLike, type?: string | null): Promise; // promisify +export { symlinkSync }; + +// read +export function read( + fd: number, + buffer: TBuffer, + offset: number, + length: number, + position: number | null +): Promise<{ bytesRead: number, buffer: TBuffer }>; // promisify +export { readSync }; + +// readdir +export function readdir( + path: PathLike, + options?: { encoding: BufferEncoding; } | 'ascii' | 'utf8' | 'utf16le' | 'ucs2' | 'base64' | 'latin1' | 'binary' | 'hex' +): Promise; // promisify +export { readdirSync }; + +// readFile +export function readFile(path: PathLike | number, callback?: (err: any, value?: string) => void): Promise; +export function readFile( + path: PathLike | number, + options?: { encoding?: string; flag?: string; escape?: boolean; }, + callback?: (err: any, value?: string) => void +): Promise; +export function readFileSync(path: PathLike | number, options?: { encoding?: string; flag?: string; escape?: boolean; }): string; + +// readlink +export function readlink(path: PathLike, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): Promise; // promisify +export function readlink(path: PathLike, options: { encoding: 'buffer' } | 'buffer'): Promise; // promisify +export function readlink(path: PathLike, options?: { encoding?: string | null } | string | null): Promise; // promisify +export { readlinkSync }; + +// realpath +export function realpath(path: PathLike, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): Promise; // promisify +export function realpath(path: PathLike, options: { encoding: 'buffer' } | 'buffer'): Promise; // promisify +export function realpath(path: PathLike, options?: { encoding?: string | null } | string | null): Promise; // promisify +export { realpathSync }; + +// rename +export function rename(oldPath: PathLike, newPath: PathLike): Promise; // promisify +export { renameSync }; + +// rmdir +export function rmdir(path: string, callback?: (err: any) => void): Promise; +export function rmdirSync(path: string): void; + +// stat +export function stat(path: PathLike): Promise; // promisify +export function fstat(fd: number): Promise; // promisify +export function lstat(path: PathLike): Promise; // promisify +export { statSync, fstatSync, lstatSync }; + +// truncate +export function truncate(path: PathLike, len?: number | null): Promise; // promisify +export function ftruncate(fd: number, len?: number | null): Promise; // promisify +export { truncateSync, ftruncateSync }; + +// unlink +export function unlink(path: PathLike): Promise; // promisify +export { unlinkSync }; + +// utimes +export function utimes(path: PathLike, atime: string | number | Date, mtime: string | number | Date): Promise; // promisify +export function futimes(fd: number, atime: string | number | Date, mtime: string | number | Date): Promise; // promisify +export { utimesSync, futimesSync }; + +// watch +import { FSWatcher, WatchOptions } from 'chokidar'; +export function watch(path: string | string[], options?: WatchOptions, callback?: (err: any, value?: FSWatcher) => void): Promise; +export { watchFile, unwatchFile }; + +// write +export function write( + fd: number, + buffer?: TBuffer, + offset?: number, + length?: number, + position?: number | null +): Promise<{ bytesWritten: number, buffer: TBuffer }>; // promisify +export function write( + fd: number, + string: any, + position?: number | null, + encoding?: string | null +): Promise<{ bytesWritten: number, buffer: string }>; // promisify +export { writeSync }; + +// writeFile +export function writeFile(path: string, data: any, callback?: (err: any) => void): Promise; +export function writeFile( + path: string, + data: any, + options?: string | { encoding?: string | null; mode?: string | number; flag?: string }, + callback?: (err: any) => void +): Promise; +export function writeFileSync(path: string, data: any, options?: string | { encoding?: string | null; mode?: string | number; flag?: string }): void; + +// Static classes +export let Stats: Stats; +export let ReadStream: ReadStream; +export let WriteStream: WriteStream; + +// util +export function escapeEOL(str: string): string; +export function escapeBOM(str: string): string; diff --git a/types/hexo-fs/tsconfig.json b/types/hexo-fs/tsconfig.json new file mode 100644 index 0000000000..ac5cf6d10d --- /dev/null +++ b/types/hexo-fs/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": [ + "es6" + ], + "module": "commonjs", + "noEmit": true, + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "hexo-fs-tests.ts" + ] +} diff --git a/types/hexo-fs/tslint.json b/types/hexo-fs/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/hexo-fs/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} From af1181038950e5f906743feb97de35db8dddd319 Mon Sep 17 00:00:00 2001 From: segayuu Date: Tue, 5 Sep 2017 11:22:38 +0900 Subject: [PATCH 2/4] added doc comments. --- types/hexo-fs/index.d.ts | 147 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 1 deletion(-) diff --git a/types/hexo-fs/index.d.ts b/types/hexo-fs/index.d.ts index eae1e79c06..8a0e96ebaa 100644 --- a/types/hexo-fs/index.d.ts +++ b/types/hexo-fs/index.d.ts @@ -68,7 +68,7 @@ import { unwatchFile, // write, writeSync - } from 'graceful-fs'; +} from 'graceful-fs'; export interface DirectoryOptions { ignoreHidden?: boolean; @@ -91,8 +91,27 @@ export let access: ((path: PathLike, mode?: number) => Promise) | undefine export let accessSync: ((path: PathLike, mode?: number) => void) | undefined; // promisify // appendFile +/** + * Appends data to a file. + * @param path + * @param data + * @param callback + */ export function appendFile(path: string, data: any, callback?: (err: any) => void): Promise; +/** + * Appends data to a file. + * @param path + * @param data + * @param options + * @param callback + */ export function appendFile(path: string, data: any, options: string | AppendFileOptions, callback?: (err: any) => void): Promise; +/** + * Synchronous version of fs.appendFile. + * @param path + * @param data + * @param options + */ export function appendFileSync(path: string, data: any, options?: string | AppendFileOptions): void; // chmod @@ -112,14 +131,37 @@ export function close(fd: number): Promise; // promisify export { closeSync }; // copy +/** + * Copies a directory from src to dest. It returns an array of copied files. + * @param src + * @param dest + * @param callback + */ export function copyDir(src: string, dest: string, callback?: (err: any, value?: string[]) => void): Promise; +/** + * Copies a directory from src to dest. It returns an array of copied files. + * @param dest + * @param options + * @param callback + */ export function copyDir(src: string, dest: string, options?: DirectoryOptions, callback?: (err: any, value?: string[]) => void): Promise; +/** + * Copies a file from src to dest. + * @param src + * @param dest + * @param callback + */ export function copyFile(src: PathLike, dest: string, callback?: (err: any) => void): Promise; // createStream export { createReadStream, createWriteStream }; // emptyDir +/** + * Deletes all files in a directory. It returns an array of deleted files. + * @param path + * @param callback + */ export function emptyDir(path: string, callback?: (err: any, value?: string | string[]) => void): Promise; export function emptyDir( path: string, @@ -129,11 +171,31 @@ export function emptyDir( export function emptyDirSync(path: string, options?: DirectoryOptions & { exclude?: string[] }, parent?: string): string | string[]; // ensurePath +/** + * Ensures the given path is available to use or appends a number to the path. + * @param path + * @param callback + */ export function ensurePath(path: string, callback?: (err: any, value?: string) => void): Promise; +/** + * Synchronous version of `fs.ensurePath`. + * @param path + */ export function ensurePathSync(path: string): string; // ensureWriteStream +/** + * Creates the parent directories if they does not exist and returns a writable stream. + * @param path + * @param callback + */ export function ensureWriteStream(path: string, callback?: (err: any, value?: WriteStream) => void): Promise; +/** + * Creates the parent directories if they does not exist and returns a writable stream. + * @param path + * @param options + * @param callback + */ export function ensureWriteStream( path: string, options?: string | { @@ -146,6 +208,11 @@ export function ensureWriteStream( }, callback?: (err: any, value?: WriteStream) => void ): Promise; +/** + * Synchronous version of fs.ensureWriteStream. + * @param path + * @param options + */ export function ensureWriteStreamSync(path: string, options?: string | { flags?: string; defaultEncoding?: string; @@ -156,7 +223,16 @@ export function ensureWriteStreamSync(path: string, options?: string | { }): WriteStream; // exists +/** + * Test whether or not the given `path` exists by checking with the file system. + * @param path checking if exists. + * @param callback + */ export function exists(path: PathLike, callback?: (exist: boolean) => void): Promise; +/** + * Synchronous version of `fs.exists`. + * @param path + */ export function existsSync(path: PathLike): boolean; // fsync @@ -168,8 +244,25 @@ export function link(existingPath: PathLike, newPath: PathLike): Promise; export { linkSync }; // listDir +/** + * Lists files in a directory. + * @param path + * @param callback + */ export function listDir(path: string, callback?: (err: any, value?: string[]) => void): Promise; +/** + * Lists files in a directory. + * @param path + * @param options + * @param callback + */ export function listDir(path: string, options?: DirectoryOptions, callback?: (err: any, value?: string[]) => void): Promise; +/** + * Synchronous version of `fs.listDir`. + * @param path + * @param options + * @param parent + */ export function listDirSync(path: string, options?: DirectoryOptions, parent?: string): string | string[]; // mkdir @@ -177,7 +270,16 @@ export function mkdir(path: PathLike, mode?: string | number): Promise; // export { mkdirSync }; // mkdirs +/** + * Creates a directory and its parent directories if they does not exist. + * @param path + * @param callback + */ export function mkdirs(path: PathLike, callback?: (err: any) => void): Promise; +/** + * Synchronous version of `fs.mkdirs`. + * @param path + */ export function mkdirsSync(path: string): void; // open @@ -206,12 +308,28 @@ export function readdir( export { readdirSync }; // readFile +/** + * Reads the entire contents of a file. + * @param path + * @param callback + */ export function readFile(path: PathLike | number, callback?: (err: any, value?: string) => void): Promise; +/** + * Reads the entire contents of a file. + * @param path + * @param options + * @param callback + */ export function readFile( path: PathLike | number, options?: { encoding?: string; flag?: string; escape?: boolean; }, callback?: (err: any, value?: string) => void ): Promise; +/** + * Synchronous version of `fs.readFile`. + * @param path + * @param options + */ export function readFileSync(path: PathLike | number, options?: { encoding?: string; flag?: string; escape?: boolean; }): string; // readlink @@ -256,6 +374,14 @@ export { utimesSync, futimesSync }; // watch import { FSWatcher, WatchOptions } from 'chokidar'; +/** + * Watches changes of a file or a directory. + * + * See Chokidar API for more info. + * @param path + * @param options + * @param callback + */ export function watch(path: string | string[], options?: WatchOptions, callback?: (err: any, value?: FSWatcher) => void): Promise; export { watchFile, unwatchFile }; @@ -276,13 +402,32 @@ export function write( export { writeSync }; // writeFile +/** + * Writes data to a file. + * @param path + * @param data + * @param callback + */ export function writeFile(path: string, data: any, callback?: (err: any) => void): Promise; +/** + * Writes data to a file. + * @param path + * @param data + * @param options + * @param callback + */ export function writeFile( path: string, data: any, options?: string | { encoding?: string | null; mode?: string | number; flag?: string }, callback?: (err: any) => void ): Promise; +/** + * Synchronous version of `fs.writeFile`. + * @param path + * @param data + * @param options + */ export function writeFileSync(path: string, data: any, options?: string | { encoding?: string | null; mode?: string | number; flag?: string }): void; // Static classes From 23c297b70d761818d939bedcd1e92c50e7155bbc Mon Sep 17 00:00:00 2001 From: segayuu Date: Tue, 5 Sep 2017 11:44:24 +0900 Subject: [PATCH 3/4] readdir typed. --- types/hexo-fs/index.d.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/types/hexo-fs/index.d.ts b/types/hexo-fs/index.d.ts index 8a0e96ebaa..5e8a595c66 100644 --- a/types/hexo-fs/index.d.ts +++ b/types/hexo-fs/index.d.ts @@ -301,10 +301,9 @@ export function read( export { readSync }; // readdir -export function readdir( - path: PathLike, - options?: { encoding: BufferEncoding; } | 'ascii' | 'utf8' | 'utf16le' | 'ucs2' | 'base64' | 'latin1' | 'binary' | 'hex' -): Promise; // promisify +export function readdir(path: PathLike, options?: { encoding: BufferEncoding | null } | BufferEncoding | null): Promise; // promisify +export function readdir(path: PathLike, options: "buffer" | { encoding: "buffer" }): Promise; // promisify +export function readdir(path: PathLike, options?: { encoding?: string | null } | string | null): Promise>; // promisify export { readdirSync }; // readFile From 927f54454cbb6a6f4e1dccd050c3fb21239efaa2 Mon Sep 17 00:00:00 2001 From: segayuu Date: Tue, 5 Sep 2017 12:12:16 +0900 Subject: [PATCH 4/4] use dts-gen. --- types/hexo-fs/index.d.ts | 7 ++----- types/hexo-fs/tsconfig.json | 4 ++-- types/hexo-fs/tslint.json | 4 +--- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/types/hexo-fs/index.d.ts b/types/hexo-fs/index.d.ts index 5e8a595c66..896fbc24eb 100644 --- a/types/hexo-fs/index.d.ts +++ b/types/hexo-fs/index.d.ts @@ -1,10 +1,7 @@ // Type definitions for hexo-fs 0.2 -// Project: https://github.com/hexojs/hexo-fs -// Definitions by: Sega Yuu +// Project: http://hexo.io/ +// Definitions by: segayuu // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.4 - -/// import Promise = require('bluebird'); import { diff --git a/types/hexo-fs/tsconfig.json b/types/hexo-fs/tsconfig.json index ac5cf6d10d..fe667f65e4 100644 --- a/types/hexo-fs/tsconfig.json +++ b/types/hexo-fs/tsconfig.json @@ -1,10 +1,9 @@ { "compilerOptions": { + "module": "commonjs", "lib": [ "es6" ], - "module": "commonjs", - "noEmit": true, "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, @@ -13,6 +12,7 @@ "../" ], "types": [], + "noEmit": true, "forceConsistentCasingInFileNames": true }, "files": [ diff --git a/types/hexo-fs/tslint.json b/types/hexo-fs/tslint.json index f93cf8562a..3db14f85ea 100644 --- a/types/hexo-fs/tslint.json +++ b/types/hexo-fs/tslint.json @@ -1,3 +1 @@ -{ - "extends": "dtslint/dt.json" -} +{ "extends": "dtslint/dt.json" }