From af442bacb3c598d4098236128b852f592e59f40c Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Fri, 6 Dec 2019 09:15:41 -0800 Subject: [PATCH] Adding additional operations 1. Added rmdirSync with recursive:true 2. Added unlinkSync, symlinkOrCopySync 3. Added tests for the same 4. Added README changes 5. Update package version --- README.md | 8 +++++++- package.json | 7 +++++-- src/index.ts | 28 ++++++++++++++++++++++++---- test/unit-test.js | 29 ++++++++++++++++++++++++++++- yarn.lock | 43 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6f94816..e51a20b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,13 @@ This libary is not intended to use independently outside broccoli or broccoli-pl * statSync * writeFileSync * appendFileSync -* rmdirSync * mkdirSync +* unlinkSync All these operations above are same as File Operations documented in node API [guide](https://nodejs.org/api/fs.html). + +* rmdirSync + +Perform same operation as node [guide](https://nodejs.org/api/fs.html#fs_fs_rmdirsync_path_options). +We have polyfilled `recursive: true` option to perform a recursive directory removal. In recursive mode, errors are not reported if path does not exist, and operations are retried on failure. Default: false +* [symlinkOrCopySync](https://github.com/broccolijs/node-symlink-or-copy#node-symlink-or-copy) \ No newline at end of file diff --git a/package.json b/package.json index 49da9ad..e7dc224 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "broccoli-output-wrapper", - "version": "3.0.0", + "version": "3.1.0", "description": "Output wrapper is a library to write output file to outputpath.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -13,9 +13,12 @@ "test:debug": "yarn build && mocha --inspect-brk -r ts-node/register" }, "dependencies": { - "heimdalljs-logger": "^0.1.10" + "fs-extra": "^8.1.0", + "heimdalljs-logger": "^0.1.10", + "symlink-or-copy": "^1.2.0" }, "devDependencies": { + "@types/fs-extra": "^8.0.1", "@types/node": "^12.11.1", "chai": "^4.2.0", "mocha": "^6.2.1", diff --git a/src/index.ts b/src/index.ts index 649b72b..2ce3afb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,8 @@ import * as fs from 'fs'; import { isAbsolute, resolve } from 'path'; import { readFileSync, existsSync, readdirSync, lstatSync, statSync, writeFileSync, appendFileSync, rmdirSync, mkdirSync } from 'fs'; +import { removeSync } from 'fs-extra'; +const symlinkOrCopySync = require('symlink-or-copy').sync; const logger = require('heimdalljs-logger')('broccoli:outputWrapper'); @@ -13,10 +15,17 @@ const WHITELISTEDOPERATION = new Set([ 'writeFileSync', 'appendFileSync', 'rmdirSync', - 'mkdirSync' + 'mkdirSync', + 'unlinkSync', + 'symlinkOrCopySync' ]); -function handleFs(target: any, propertyName: string, node: any, relativePath: string, ...fsArguments: Array) { +function handleFs(target: any, propertyName: string, node: any, relativePath: string, ...fsArguments: Array) { + let srcPath = ''; + if (propertyName === 'symlinkOrCopySync') { + srcPath = relativePath; + relativePath = fsArguments[0]; + } if (isAbsolute(relativePath)) { throw new Error(`Relative path is expected, path ${relativePath} is an absolute path.`); } @@ -26,7 +35,16 @@ function handleFs(target: any, propertyName: string, node: any, relativePath: st } if(WHITELISTEDOPERATION.has(propertyName)) { logger.debug(`[operation:${propertyName}] at ${outputPath}`); - return target[propertyName](outputPath, ...fsArguments); + switch (propertyName) { + case 'symlinkOrCopySync': + return symlinkOrCopySync(srcPath, outputPath); + case 'rmdirSync': + if (fsArguments[0] && fsArguments[0].recursive) { + return removeSync(outputPath); + } + default: + return target[propertyName](outputPath, ...fsArguments); + } } else { throw new Error(`Operation ${propertyName} is not allowed to use. Allowed operations are ${Array.from(WHITELISTEDOPERATION).toString()}`); } @@ -51,6 +69,8 @@ namespace outputWrapper { writeFileSync: typeof writeFileSync, appendFileSync: typeof appendFileSync, rmdirSync: typeof rmdirSync, - mkdirSync: typeof mkdirSync + mkdirSync: typeof mkdirSync, + unlinkSync: typeof fs.unlinkSync, + symlinkOrCopy: (srcPath: string, destPath: string) => void } } \ No newline at end of file diff --git a/test/unit-test.js b/test/unit-test.js index 0f5553f..01a3d78 100644 --- a/test/unit-test.js +++ b/test/unit-test.js @@ -2,6 +2,7 @@ const buildOutputWrapper = require('../src'); const tmp = require('tmp'); const fs = require('fs'); const { expect } = require('chai'); +const path = require('path'); describe('output-wrapper', function() { let output, temp, node; @@ -34,10 +35,36 @@ describe('output-wrapper', function() { it(`should not allow other fs operations`, function() { expect(() => output.writevSync('test.md', 'test')).to.throw( - `Operation writevSync is not allowed to use. Allowed operations are readFileSync,existsSync,lstatSync,readdirSync,statSync,writeFileSync,appendFileSync,rmdirSync,mkdirSync` + /^Operation writevSync is not allowed to use. Allowed operations are readFileSync,existsSync,lstatSync,readdirSync,statSync,writeFileSync,appendFileSync,rmdirSync,mkdirSync,unlinkSync,symlinkOrCopySync$/ ); }); + it('can remove folder recursively', function() { + output.mkdirSync('test'); + expect(fs.existsSync(`${temp.name}/test`)).to.be.true; + output.writeFileSync('test.md', 'test'); + output.rmdirSync('./', { + recursive: true + }); + expect(fs.existsSync(`${temp.name}/test`)).to.be.false; + }); + + it('can remove folder non recursive', function() { + output.mkdirSync('test'); + expect(fs.existsSync(`${temp.name}/test`)).to.be.true; + expect(()=> output.rmdirSync('./')).to.throw(Error); + output.rmdirSync('test'); + expect(fs.existsSync(`${temp.name}/test`)).to.be.false; + }); + + it('can symlinkOrCopySync', function () { + let temp_in = tmp.dirSync().name; + fs.writeFileSync(`${temp_in}/test.md`, 'test'); + output.symlinkOrCopySync(`${temp_in}/test.md`, `test.md`); + expect(fs.realpathSync(`${temp.name}/test.md`)).to.be.contains(path.join(temp_in,'test.md')); + expect(output.lstatSync('test.md').isSymbolicLink()).to.be.true; + }); + it(`should throw if the dir strutcture doesn't exist and attempt to write`, function() { expect(() => output.writeFileSync('test/test.md', 'test')).to.throw( /.*no such file or directory.*/ diff --git a/yarn.lock b/yarn.lock index fb0087b..b593b66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,18 @@ # yarn lockfile v1 +"@types/fs-extra@^8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686" + integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "12.12.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.14.tgz#1c1d6e3c75dba466e0326948d56e8bd72a1903d2" + integrity sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA== + "@types/node@^12.11.1": version "12.11.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.1.tgz#1fd7b821f798b7fa29f667a1be8f3442bb8922a3" @@ -223,6 +235,15 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -267,6 +288,11 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" @@ -369,6 +395,13 @@ js-yaml@3.13.1: argparse "^1.0.7" esprima "^4.0.0" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -650,6 +683,11 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +symlink-or-copy@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" + integrity sha512-W31+GLiBmU/ZR02Ii0mVZICuNEN9daZ63xZMPDsYgPgNjMtg+atqLEGI7PPI936jYSQZxoLb/63xos8Adrx4Eg== + tmp@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" @@ -678,6 +716,11 @@ typescript@^3.6.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"