From cb32e915243feac6f97d8d7c28fe96b2a41febf1 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Mon, 1 Jun 2020 01:56:21 -0300 Subject: [PATCH] Misc improvements and fixes. (#147) --- .github/workflows/test.yml | 20 ++++++++++++++ README.md | 2 ++ __tests__/copy-tpl.js | 26 +++++++++++++++++++ __tests__/copy.js | 2 +- .../fixtures/ejs/file-ejs-extension.txt.ejs | 0 __tests__/fixtures/file-circular.txt | 1 + lib/actions/append.js | 8 +++--- lib/actions/copy-tpl.js | 9 ++++--- lib/actions/copy.js | 6 ++--- package.json | 3 +++ 10 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 __tests__/fixtures/ejs/file-ejs-extension.txt.ejs create mode 100644 __tests__/fixtures/file-circular.txt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..562b775 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,20 @@ +name: Node.js CI + +on: [push, pull_request] + +jobs: + build: + name: Node ${{ matrix.node-version }} + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x, 12.x] + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm test diff --git a/README.md b/README.md index cb6f8d6..3212952 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ Optionally, pass an `options.process` function (`process(contents)`) returning a `from` can be a glob pattern that'll be match against the file system. If that's the case, then `to` must be an output directory. For a globified `from`, you can optionally pass in an `options.globOptions` object to change its pattern matching behavior. The full list of options are being described [here](https://github.com/mrmlnc/fast-glob#options-1). The `nodir` flag is forced to be `true` in `globOptions` to ensure a vinyl object representing each matching directory is marked as `deleted` in the `mem-fs` store. +Optionally, when `from` is a glob pattern, pass an `options.processDestinationPath` function (`processDestinationPath(destinationFile)`) returning a string who'll become the new file name. + ### `#copyTpl(from, to, context[, templateOptions [, copyOptions]])` Copy the `from` file and, if it is not a binary file, parse its content as an [ejs](http://ejs.co/) template where `context` is the template context (the variable names available inside the template). diff --git a/__tests__/copy-tpl.js b/__tests__/copy-tpl.js index 65c392a..1ea6fc6 100644 --- a/__tests__/copy-tpl.js +++ b/__tests__/copy-tpl.js @@ -68,4 +68,30 @@ describe('#copyTpl()', () => { fs.copyTpl(pathCopied, newPath); expect(fs.read(newPath)).toBe(fs.read(filepath)); }); + + it('allow passing circular function context', function () { + const b = {}; + const a = {name: 'new content', b}; + b.a = a; + const filepath = path.join(__dirname, 'fixtures/file-circular.txt'); + const newPath = '/new/path/file.txt'; + fs.copyTpl(filepath, newPath, {}, { + context: {a} + }); + expect(fs.read(newPath)).toBe('new content new content' + os.EOL); + }); + + it('removes ejs extension when globbing', function () { + const filepath = path.join(__dirname, 'fixtures/ejs'); + const newPath = '/new/path/'; + fs.copyTpl(filepath, newPath); + expect(fs.exists(path.join(newPath, 'file-ejs-extension.txt'))).toBeTruthy(); + }); + + it('doens\'t removes ejs extension when not globbing', function () { + const filepath = path.join(__dirname, 'fixtures/ejs/file-ejs-extension.txt.ejs'); + const newPath = '/new/path/file-ejs-extension.txt.ejs'; + fs.copyTpl(filepath, newPath); + expect(fs.exists(newPath)).toBeTruthy(); + }); }); diff --git a/__tests__/copy.js b/__tests__/copy.js index 90122f0..5954181 100644 --- a/__tests__/copy.js +++ b/__tests__/copy.js @@ -84,7 +84,7 @@ describe('#copy()', () => { let outputDir = path.join(__dirname, '../test/output'); const process = sinon.stub().returnsArg(0); fs.copy(path.join(__dirname, '/fixtures/**'), outputDir, {process}); - sinon.assert.callCount(process, 8); // 7 total files under 'fixtures', not counting folders + sinon.assert.callCount(process, 10); // 8 total files under 'fixtures', not counting folders expect(fs.read(path.join(outputDir, 'file-a.txt'))).toBe('foo' + os.EOL); expect(fs.read(path.join(outputDir, '/nested/file.txt'))).toBe('nested' + os.EOL); }); diff --git a/__tests__/fixtures/ejs/file-ejs-extension.txt.ejs b/__tests__/fixtures/ejs/file-ejs-extension.txt.ejs new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/file-circular.txt b/__tests__/fixtures/file-circular.txt new file mode 100644 index 0000000..0239511 --- /dev/null +++ b/__tests__/fixtures/file-circular.txt @@ -0,0 +1 @@ +<%= this.a.name %> <%= this.a.b.a.name %> diff --git a/lib/actions/append.js b/lib/actions/append.js index a4d12a2..f42ae76 100644 --- a/lib/actions/append.js +++ b/lib/actions/append.js @@ -1,13 +1,13 @@ 'use strict'; -var extend = require('deep-extend'); var EOL = require('os').EOL; module.exports = function (to, contents, options) { - options = extend({ + options = { trimEnd: true, - separator: EOL - }, options || {}); + separator: EOL, + ...options + }; var currentContents = this.read(to); if (options.trimEnd) { diff --git a/lib/actions/copy-tpl.js b/lib/actions/copy-tpl.js index 381a82a..70a08d7 100644 --- a/lib/actions/copy-tpl.js +++ b/lib/actions/copy-tpl.js @@ -1,6 +1,5 @@ 'use strict'; -var extend = require('deep-extend'); var ejs = require('ejs'); var isBinaryFileSync = require('isbinaryfile').isBinaryFileSync; @@ -15,7 +14,7 @@ function render(contents, filename, context, tplSettings) { contents.toString(), context, // Setting filename by default allow including partials. - extend({filename: filename}, tplSettings) + {filename: filename, ...tplSettings} ); } @@ -29,11 +28,13 @@ module.exports = function (from, to, context, tplSettings, options) { this.copy( from, to, - extend(options || {}, { + { + processDestinationPath: path => path.replace(/.ejs$/, ''), + ...options, process: function (contents, filename) { return render(contents, filename, context, tplSettings); } - }), + }, context, tplSettings ); diff --git a/lib/actions/copy.js b/lib/actions/copy.js index fa4ac69..81059af 100644 --- a/lib/actions/copy.js +++ b/lib/actions/copy.js @@ -5,7 +5,6 @@ var fs = require('fs'); var path = require('path'); var glob = require('glob'); var globby = require('globby'); -var extend = require('deep-extend'); var multimatch = require('multimatch'); var ejs = require('ejs'); var util = require('../util'); @@ -20,7 +19,7 @@ exports.copy = function (from, to, options, context, tplSettings) { options = options || {}; var fromGlob = util.globify(from); - var globOptions = extend(options.globOptions || {}, {nodir: true}); + var globOptions = {...options.globOptions, nodir: true}; var diskFiles = globby.sync(fromGlob, globOptions); var storeFiles = []; this.store.each(file => { @@ -38,10 +37,11 @@ exports.copy = function (from, to, options, context, tplSettings) { 'When copying multiple files, provide a directory as destination' ); + const processDestinationPath = options.processDestinationPath || (path => path); var root = util.getCommonPath(from); generateDestination = filepath => { var toFile = path.relative(root, filepath); - return path.join(to, toFile); + return processDestinationPath(path.join(to, toFile)); }; } diff --git a/package.json b/package.json index f10835d..3c1955b 100644 --- a/package.json +++ b/package.json @@ -39,5 +39,8 @@ "collectCoverage": true, "coverageDirectory": "coverage", "testEnvironment": "node" + }, + "engines": { + "node": ">=10.0.0" } }