diff --git a/.travis.yml b/.travis.yml index 4460917..1f61ed0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,24 @@ +dist: trusty +sudo: required language: node_js -node_js: - - "node" - - "lts/*" \ No newline at end of file +cache: yarn +matrix: + include: + - name: "Standard linting" + script: yarn standard + node_js: "lts/*" + - name: "Unit tests & coverage" + script: yarn test + node_js: + - "node" + - "lts/*" + - name: "Benchmark test - glob" + script: yarn test:benchmark:glob + node_js: + - "node" + - "lts/*" + - name: "Benchmark test - string" + script: yarn test:benchmark:string + node_js: + - "node" + - "lts/*" \ No newline at end of file diff --git a/README.md b/README.md index 02dd531..3aaa06b 100644 --- a/README.md +++ b/README.md @@ -230,23 +230,22 @@ FRS-replace a b --content abcd -o foo_replaced.js FRS-replace a b -i foo.js | ``` -## Benchmarks +## Benchmarks (Node v10.11.0) #### input as glob pattern [1000 iterations x 100 repetitions] | Library (best bolded) | Execution time [s] | Difference percentage (comparing to best time) | | --- | --- | --- | -| **FRS-replace async** | 0.07656150 | 0.0000% | -| FRS-replace sync | 0.31196953 | 307.4757% | -| replace-in-file | 0.76240075 | 895.8017% | -| replace async | 0.11774627 | 53.7931% | -| replace sync | 0.91518713 | 1095.3620% | +| **FRS-replace async** | 0.15219495 | 0.0000% | +| FRS-replace sync | 0.62943626 | 313.5724% | +| replace-in-file | 1.80808213 | 1088.0040% | +| replace async | 0.21353394 | 40.3029% | +| replace sync | 1.53610279 | 909.2995% | | replace-string | *N/A* | *N/A* | #### input & replacement as strings [1000 iterations x 100 repetitions] | Library (best bolded) | Execution time [s] | Difference percentage (comparing to best time) | | --- | --- | --- | -| FRS-replace async | 0.00511845 | 77.4972% | -| **FRS-replace sync** | 0.00288368 | 0.0000% | +| FRS-replace async | 0.04848095 | 194.2632% | +| **FRS-replace sync** | 0.01647537 | 0.0000% | | replace-in-file | *N/A* | *N/A* | | replace async | *N/A* | *N/A* | | replace sync | *N/A* | *N/A* | -| replace-string | 0.00292622 | 1.4752% | - +| replace-string | 0.01843529 | 11.8961% | diff --git a/benchmark/multiple-file-replace.benchmark.test.js b/benchmark/multiple-file-replace.benchmark.test.js index 4c110af..7626645 100644 --- a/benchmark/multiple-file-replace.benchmark.test.js +++ b/benchmark/multiple-file-replace.benchmark.test.js @@ -16,8 +16,8 @@ const content = `aąbcćdeęfg%hi jklmn oópqr,stuvwxyZ` const tmpPrefixes = { - input: 'FRS-replace-replace-in', - output: 'FRS-replace-replace-out' + input: 'FRS-replace-replace-in-', + output: 'FRS-replace-replace-out-' } const defaults = { inputReadOptions: 'utf8', @@ -26,7 +26,33 @@ const defaults = { } const repetitionsNo = 100000 const iterationsNo = 1000 -const testInput = {} +const inputFilesNo = 40 +const testInput = { + FRSReplace: { + regex, + replacement + }, + + replace: { + regex, + replacement, + recursive: true, + silent: true + }, + + replaceAsync: { + regex, + replacement, + async: true, + recursive: true, + silent: true + }, + + replaceInFile: { + from: regex, + to: replacement + } +} const testedLibraries = [ 'FRS-replace async', 'FRS-replace sync', @@ -36,11 +62,9 @@ const testedLibraries = [ 'replace-string' ] -let dir, output, input - -const readmeContent = fs.readFileSync('./README.md').toString() - +let dir; let output; let inputs = [] let perfyResults = '' +let tmpFilesPromise { const dirObj = tmp.dirSync() // removing all files similar our tmp @@ -53,62 +77,42 @@ let perfyResults = '' ].map(v => v + '*') ) .forEach(fs.unlinkSync) -} - -tap.beforeEach(async () => { - testInput.FRSReplace = { - regex, - replacement - } - - testInput.replace = { - regex, - replacement, - recursive: true, - silent: true - } - - testInput.replaceAsync = { - regex, - replacement, - async: true, - recursive: true, - silent: true - } - testInput.replaceInFile = { - from: regex, - to: replacement + const promises = [] + + for (let i = 0; i < inputFilesNo; ++i) { + promises.push( + tmp.file({ prefix: tmpPrefixes.input + i + '-', keep: true, dir }) + .then(input => { + inputs.push(input) + return new Promise(resolve => { + fs.appendFile(input.path, content, { encoding: defaults.inputReadOptions }, resolve) + }) + }) + ) } - cleanInputs() - - await tmp.file({ prefix: tmpPrefixes.input, keep: true, dir }) - .then( - async f => { - input = f - return new Promise( - resolve => fs.appendFile(f.path, content, { encoding: defaults.inputReadOptions }, resolve) - ) - }) -}) - -const cleanInputs = (done) => { - input && input.cleanup() - input = undefined - done && done() // to be runned either by node-tap or manually + tmpFilesPromise = Promise.all(promises) } - -tap.afterEach((done) => { +tap.autoend(false) +tap.beforeEach(() => tmpFilesPromise) +tap.afterEach(done => { fs.existsSync(output) && fs.unlinkSync(output) - cleanInputs() done() }) -tap.test(`input as glob pattern [${iterationsNo} iterations x ${repetitionsNo / iterationsNo} repetitions]`, async ct => { +tap.teardown(() => { + inputs.forEach(input => input.cleanup) + inputs = [] + const readmeContent = fs.readFileSync('./README.md').toString() + + fs.writeFileSync('./README.md', readmeContent.replace(/(##\sBenchmarks \(Node )(?:.*?)(\)\s)[\s\S]*?(?:$|(?:\s##\s))/, `$1${process.version}$2${perfyResults}`)) +}) + +tap.test(`input as glob pattern [${inputFilesNo} files x ${iterationsNo} iterations x ${repetitionsNo / iterationsNo} repetitions]`, async ct => { const results = await multipleTests(ct, [ { - fn: () => { FRSreplace.async(testInput.FRSReplace) }, // IMPORTANT: test doesn't wait for function to finish, because replace (async) doesn't support that kind of behaviour (https://github.com/harthur/replace/issues/25) + fn: () => FRSreplace.async(testInput.FRSReplace), before: () => (testInput.FRSReplace.input = `${dir}/${tmpPrefixes.input}*`) }, { @@ -119,12 +123,7 @@ tap.test(`input as glob pattern [${iterationsNo} iterations x ${repetitionsNo / fn: () => replaceInFile(testInput.replaceInFile), before: () => (testInput.replaceInFile.files = `${dir}/${tmpPrefixes.input}*`) }, - { - fn: () => replace(testInput.replaceAsync), - before: () => { - testInput.replaceAsync.paths = [dir.replace(/\\/g, '/')] - } - }, + undefined, // IMPORTANT: test doesn't checks replace async, because it doesn't returns when (and if) file got replaced(https://github.com/harthur/replace/issues/25) { fn: () => replace(testInput.replace), before: () => { @@ -133,12 +132,12 @@ tap.test(`input as glob pattern [${iterationsNo} iterations x ${repetitionsNo / }, undefined ]) - const sortedResults = results.slice().sort(sortByNanoseconds) - ct.is((sortedResults[0].name.indexOf('FRS-replace') !== -1 || (sortedResults[1].name.indexOf('FRS-replace') !== -1 && sortedResults[1].avgPercentageDifference < 5)), true, 'FRS-replace should be the fastest or second, but at most with 5% difference to best') - ct.not(sortedResults[2].name.indexOf('FRS-replace sync'), -1, 'FRS-replace sync should be third (right after async replace)') + const result = outputPerfy(ct, results, results.slice().sort(sortByNumberVariable('fullNanoseconds'))[0]) + const sortedResults = result.results.slice().sort(sortByNumberVariable('avgTime')) - outputPerfy(ct, results, sortedResults[0]) + ct.is((sortedResults[0].name.indexOf('FRS-replace sync') !== -1 || (sortedResults[1].name.indexOf('FRS-replace sync') !== -1 && sortedResults[1].avgPercentageDifference < 5)), true, 'FRS-replace sync should be the fastest or second, but at most with 5% difference to best') + ct.is(sortedResults[0].name.indexOf('FRS-replace async') !== -1 || sortedResults[1].name.indexOf('FRS-replace async') !== -1, true, 'FRS-replace async should be the fastest or second') ct.end() }) @@ -165,19 +164,14 @@ tap.test(`input & replacement as strings [${iterationsNo} iterations x ${repetit { fn: () => replaceString(content, regex.source, replacement) } ]) - const result = outputPerfy(ct, results, results.slice().sort(sortByNanoseconds)[0]) - - const sortedResults = result.results.slice().sort(sortByNanoseconds) + const result = outputPerfy(ct, results, results.slice().sort(sortByNumberVariable('fullNanoseconds'))[0]) + const sortedResults = result.results.slice().sort(sortByNumberVariable('avgTime')) ct.is((sortedResults[0].name.indexOf('FRS-replace') !== -1 || (sortedResults[1].name.indexOf('FRS-replace') !== -1 && sortedResults[1].avgPercentageDifference < 10)), true, 'FRS-replace should be the fastest or second, but at most with 10% difference to best') ct.end() }) -tap.teardown(() => { - fs.writeFileSync('./README.md', readmeContent.replace(/(##\sBenchmarks\s\s)[\s\S]*?(?:$|(?:\s##\s))/, '$1' + perfyResults)) -}) - function outputPerfy (t, testResults, best) { best = best.fullNanoseconds @@ -218,7 +212,7 @@ function outputPerfy (t, testResults, best) { ) perfyResults += - '#### ' + result.name + '\n' + + '\n### ' + result.name + '\n\n' + '| Library (best bolded) | Execution time [s] | Difference percentage (comparing to best time) |\n' + '| --- | --- | --- |\n' + result.results.reduce( @@ -250,13 +244,12 @@ async function multipleTests (t, testCfgs, n, iterations) { const testCfgLen = testCfgs.length - for (let i = 0; i < n; ++i) { - for (let k = testCfgLen - 1; k >= 0; --k) { - const { v: testCfg, i: index } = testCfgs[k] - const prevResult = results[index] - const libName = testedLibraries[index] - - await t.test(`${t.name} - ${libName} #${i}`, async ct => { + for (let k = testCfgLen - 1; k >= 0; --k) { + const { v: testCfg, i: index } = testCfgs[k] + const prevResult = results[index] + const libName = testedLibraries[index] + await t.test(`${t.name} - ${libName}`, async ct => { + for (let i = 0; i < n; ++i) { testCfg.before && testCfg.before() const result = await singleTest(libName, testCfg.fn, iterations) @@ -270,10 +263,9 @@ async function multipleTests (t, testCfgs, n, iterations) { } } } - - ct.end() - }) - } + } + ct.end() + }) } testCfgs.forEach(({ i: index }) => { @@ -305,14 +297,19 @@ async function singleTest (name, test, n) { return result } -function sortByNanoseconds (a, b) { - if (a.fullNanoseconds === undefined) { - return b.fullNanoseconds === undefined ? 0 : 1 - } +function sortByNumberVariable (varName) { + return (a, b) => { + a = a[varName] + b = b[varName] - if (b.fullNanoseconds === undefined) { - return -1 - } + if (a === undefined || a === null) { + return b === undefined || b === null ? 0 : 1 + } + + if (b === undefined || b === null) { + return -1 + } - return a.fullNanoseconds - b.fullNanoseconds + return a - b + } } diff --git a/benchmark/replace.spec.js b/benchmark/replace.spec.js deleted file mode 100644 index 4c110af..0000000 --- a/benchmark/replace.spec.js +++ /dev/null @@ -1,318 +0,0 @@ -const tap = require('tap') -const tmp = require('tmp-promise') -const path = require('path') -const fs = require('fs') -const perfy = require('perfy') -const glob = require('fast-glob') - -const FRSreplace = require('../src/replace') -const replace = require('replace') -const replaceInFile = require('replace-in-file') -const replaceString = require('replace-string') - -const regex = new RegExp('^[adjox]', 'gm') -const replacement = 'ą|' -const content = `aąbcćdeęfg%hi -jklmn -oópqr,stuvwxyZ` -const tmpPrefixes = { - input: 'FRS-replace-replace-in', - output: 'FRS-replace-replace-out' -} -const defaults = { - inputReadOptions: 'utf8', - outputWriteOptions: 'utf8', - inputJoinString: '\n' -} -const repetitionsNo = 100000 -const iterationsNo = 1000 -const testInput = {} -const testedLibraries = [ - 'FRS-replace async', - 'FRS-replace sync', - 'replace-in-file', - 'replace async', - 'replace sync', - 'replace-string' -] - -let dir, output, input - -const readmeContent = fs.readFileSync('./README.md').toString() - -let perfyResults = '' - -{ - const dirObj = tmp.dirSync() // removing all files similar our tmp - dir = dirObj.name - - glob.sync( - [ - path.join(dir, tmpPrefixes.input), - path.join(dir, tmpPrefixes.output) - ].map(v => v + '*') - ) - .forEach(fs.unlinkSync) -} - -tap.beforeEach(async () => { - testInput.FRSReplace = { - regex, - replacement - } - - testInput.replace = { - regex, - replacement, - recursive: true, - silent: true - } - - testInput.replaceAsync = { - regex, - replacement, - async: true, - recursive: true, - silent: true - } - - testInput.replaceInFile = { - from: regex, - to: replacement - } - - cleanInputs() - - await tmp.file({ prefix: tmpPrefixes.input, keep: true, dir }) - .then( - async f => { - input = f - return new Promise( - resolve => fs.appendFile(f.path, content, { encoding: defaults.inputReadOptions }, resolve) - ) - }) -}) - -const cleanInputs = (done) => { - input && input.cleanup() - input = undefined - done && done() // to be runned either by node-tap or manually -} - -tap.afterEach((done) => { - fs.existsSync(output) && fs.unlinkSync(output) - cleanInputs() - done() -}) - -tap.test(`input as glob pattern [${iterationsNo} iterations x ${repetitionsNo / iterationsNo} repetitions]`, async ct => { - const results = await multipleTests(ct, [ - { - fn: () => { FRSreplace.async(testInput.FRSReplace) }, // IMPORTANT: test doesn't wait for function to finish, because replace (async) doesn't support that kind of behaviour (https://github.com/harthur/replace/issues/25) - before: () => (testInput.FRSReplace.input = `${dir}/${tmpPrefixes.input}*`) - }, - { - fn: () => FRSreplace.sync(testInput.FRSReplace), - before: () => (testInput.FRSReplace.input = `${dir}/${tmpPrefixes.input}*`) - }, - { - fn: () => replaceInFile(testInput.replaceInFile), - before: () => (testInput.replaceInFile.files = `${dir}/${tmpPrefixes.input}*`) - }, - { - fn: () => replace(testInput.replaceAsync), - before: () => { - testInput.replaceAsync.paths = [dir.replace(/\\/g, '/')] - } - }, - { - fn: () => replace(testInput.replace), - before: () => { - testInput.replace.paths = [dir.replace(/\\/g, '/')] - } - }, - undefined - ]) - const sortedResults = results.slice().sort(sortByNanoseconds) - - ct.is((sortedResults[0].name.indexOf('FRS-replace') !== -1 || (sortedResults[1].name.indexOf('FRS-replace') !== -1 && sortedResults[1].avgPercentageDifference < 5)), true, 'FRS-replace should be the fastest or second, but at most with 5% difference to best') - ct.not(sortedResults[2].name.indexOf('FRS-replace sync'), -1, 'FRS-replace sync should be third (right after async replace)') - - outputPerfy(ct, results, sortedResults[0]) - - ct.end() -}) - -tap.test(`input & replacement as strings [${iterationsNo} iterations x ${repetitionsNo / iterationsNo} repetitions]`, async ct => { - const results = await multipleTests(ct, [ - { - fn: () => FRSreplace.async(testInput.FRSReplace), - before: () => { - testInput.FRSReplace.regex = regex.source - testInput.FRSReplace.content = content - } - }, - { - fn: () => FRSreplace.sync(testInput.FRSReplace), - before: () => { - testInput.FRSReplace.regex = regex.source - testInput.FRSReplace.content = content - } - }, - undefined, - undefined, - undefined, - { fn: () => replaceString(content, regex.source, replacement) } - ]) - - const result = outputPerfy(ct, results, results.slice().sort(sortByNanoseconds)[0]) - - const sortedResults = result.results.slice().sort(sortByNanoseconds) - - ct.is((sortedResults[0].name.indexOf('FRS-replace') !== -1 || (sortedResults[1].name.indexOf('FRS-replace') !== -1 && sortedResults[1].avgPercentageDifference < 10)), true, 'FRS-replace should be the fastest or second, but at most with 10% difference to best') - - ct.end() -}) - -tap.teardown(() => { - fs.writeFileSync('./README.md', readmeContent.replace(/(##\sBenchmarks\s\s)[\s\S]*?(?:$|(?:\s##\s))/, '$1' + perfyResults)) -}) - -function outputPerfy (t, testResults, best) { - best = best.fullNanoseconds - - const result = { - name: t.name, - results: testResults.reduce( - (p, v) => p.push({ - name: v.name, - avgTime: - ( - v.fullNanoseconds === undefined - ? null - : (v.fullNanoseconds / 1000000000) - ), - avgPercentageDifference: - ( - v.fullNanoseconds === undefined - ? null - : ((v.fullNanoseconds / best - 1) * 100) - ) - }) && p, - [] - ) - } - - t.parser.write( - ' ---\n' + - ' name: \'' + result.name + '\'\n' + - ' results: \n' + result.results.reduce( - (p, v) => p + - ' - name: \'' + v.name + '\'\n' + - ' avgTime: ' + v.avgTime + '\n' + - ' avgPercentageDifference: ' + v.avgPercentageDifference + '\n' - , - '' - ) + - ' ...\n\n' - ) - - perfyResults += - '#### ' + result.name + '\n' + - '| Library (best bolded) | Execution time [s] | Difference percentage (comparing to best time) |\n' + - '| --- | --- | --- |\n' + - result.results.reduce( - (p, v) => p + - '| ' + (v.avgTime * 1000000000 === best ? ('**' + v.name + '**') : v.name) + - ' | ' + (v.avgTime === null ? '*N/A*' : (v.avgTime.toFixed(8))) + - ' | ' + (v.avgPercentageDifference == null ? '*N/A*' : (v.avgPercentageDifference.toFixed(4) + '%')) + ' |\n' - , - '' - ) - - return result -} - -async function multipleTests (t, testCfgs, n, iterations) { - const results = [] - - n = (n || repetitionsNo) / iterationsNo - iterations = iterations || iterationsNo - - testCfgs = testCfgs.reduce((p, v, i) => { - if (v === undefined) { - results[i] = { name: testedLibraries[i] } - return p - } - - return p.concat({ i, v }) - }, []) - - const testCfgLen = testCfgs.length - - for (let i = 0; i < n; ++i) { - for (let k = testCfgLen - 1; k >= 0; --k) { - const { v: testCfg, i: index } = testCfgs[k] - const prevResult = results[index] - const libName = testedLibraries[index] - - await t.test(`${t.name} - ${libName} #${i}`, async ct => { - testCfg.before && testCfg.before() - const result = await singleTest(libName, testCfg.fn, iterations) - - if (!prevResult) { - results[index] = result - result.testCfg = testCfg - } else { - for (const prop in result) { - if (Object.prototype.hasOwnProperty.call(result, prop) && typeof result[prop] === 'number') { - prevResult[prop] += result[prop] - } - } - } - - ct.end() - }) - } - } - - testCfgs.forEach(({ i: index }) => { - const result = results[index] - - for (const prop in result) { - if (Object.prototype.hasOwnProperty.call(result, prop) && typeof result[prop] === 'number') { - result[prop] /= n - } - } - }) - - return results -} - -async function singleTest (name, test, n) { - n = n || repetitionsNo - - perfy.start(name) - - while (--n) { - await test() - } - - const testResult = await test() - const result = perfy.end(name) - - result.result = testResult - return result -} - -function sortByNanoseconds (a, b) { - if (a.fullNanoseconds === undefined) { - return b.fullNanoseconds === undefined ? 0 : 1 - } - - if (b.fullNanoseconds === undefined) { - return -1 - } - - return a.fullNanoseconds - b.fullNanoseconds -} diff --git a/package.json b/package.json index bf2854f..9f1d482 100644 --- a/package.json +++ b/package.json @@ -35,15 +35,18 @@ "javascript" ], "scripts": { - "prerelease": "standard --fix && yarn test", + "prerelease": "yarn standard:fix && yarn test && yarn test:benchmark", "release": "standard-version", "postrelease": "git push --follow-tags origin master && yarn publish", "pretest": "standard", - "test": "yarn test:unit --100 && yarn test:benchmark", + "test": "yarn test:unit --100", "posttest": "tap --coverage-report=html", - "pretest:unit": "standard --fix", + "pretest:unit": "yarn standard:fix", "test:unit": "tap ./src/*.test.js ./bin/*.test.js -J", - "test:benchmark": "tap ./benchmark/*.benchmark.test.js --no-timeout" + "test:benchmark": "tap ./benchmark/*.benchmark.test.js --no-timeout --no-coverage", + "test:benchmark:glob": "yarn test:benchmark --grep=\"/input as glob pattern/\"", + "test:benchmark:string": "yarn test:benchmark --grep=\"/input & replacement as strings/\"", + "standard:fix": "standard --fix" }, "devDependencies": { "perfy": "^1.1.5", @@ -58,7 +61,7 @@ "dependencies": { "fast-glob": "^3.1.0", "get-stdin": "^7.0.0", - "yargs": "^14.2.0", - "write": "^2.0.0" + "write": "^2.0.0", + "yargs": "^14.2.0" } } diff --git a/src/replace.js b/src/replace.js index a22f5d0..c27c8b2 100644 --- a/src/replace.js +++ b/src/replace.js @@ -14,14 +14,13 @@ function replaceSync ({ regex, replacement }) { - let result + let result = '' const replaceFn = typeof regex === 'string' ? replaceString : replaceRegex if (content !== undefined) { result = replaceFn(content, regex, replacement) } else if (input !== undefined) { - const files = require('fast-glob') - .sync(input, inputGlobOptions) + const files = require('fast-glob').sync(input, inputGlobOptions) if (files.length !== 0) { const fs = require('fs') @@ -30,8 +29,6 @@ function replaceSync ({ for (let i = 1, len = files.length; i < len; ++i) { result += inputJoinString + replaceFn(fs.readFileSync(files[i], inputReadOptions), regex, replacement) } - } else { - result = '' } } else { writeError('at least one input source must be defined!') @@ -62,33 +59,41 @@ async function replaceAsync ({ let result const replaceFn = typeof regex === 'string' ? replaceString : replaceRegex - if (content !== void 0) { + if (content !== undefined) { result = replaceFn(content, regex, replacement) - } else if (input !== void 0) { - const fileStream = await require('fast-glob').stream(input, inputGlobOptions) - let filesFound = false - - result = '' - - const fileReaderPromise = multiFileReaderBuilder(require('fs'), inputReadOptions, fileReader => { - fileStream.on('data', entry => { - filesFound = true - return fileReader( - entry, - content => (result += replaceFn(content, regex, replacement)) - ) - }) - fileStream.once('error', writeError) - }) - - await new Promise((resolve) => fileStream.once('end', () => { - return resolve(filesFound ? fileReaderPromise : void 0) - })) + } else if (input !== undefined) { + const fileStream = require('fast-glob').stream(input, inputGlobOptions) + const fs = require('fs') + const replacePromises = [] + const createReplacePromise = path => { + return new Promise((resolve, reject) => + fs.readFile(path, inputReadOptions, (error, data) => { + /* istanbul ignore next */ + error && reject(error) + + resolve(replaceFn(data, regex, replacement)) + }) + ) + } + + fileStream.on('error', writeError) + fileStream.on('data', path => replacePromises.push( + createReplacePromise(path) + )) + + await new Promise(resolve => + fileStream.once('end', () => + resolve(Promise.all(replacePromises)) + ) + ).then( + (strings) => (result = strings.join(inputJoinString)), + writeError + ) } else { writeError('at least one input source must be defined!') } - if (output !== void 0) { + if (output !== undefined) { if (typeof outputWriteOptions === 'string') { outputWriteOptions = { encoding: outputWriteOptions } } @@ -103,28 +108,6 @@ function writeError (msg) { throw new Error(`FRS-replace :: ${msg}`) } -function multiFileReaderBuilder (fs, inputReadOptions, setup) { - let i = 0 - return new Promise((resolve, reject) => { - setup((path, callback) => { - if (++i < 1) return - - fs.readFile(path, inputReadOptions, (error, data) => { - if (error) { - i = -1 - return reject(error) - } - - callback(data) - - if (--i === 0) { - resolve() - } - }) - }) - }) -} - function replaceRegex (content, needle, replacement) { return content.replace(needle, replacement) } diff --git a/src/replace.spec.test.js b/src/replace.spec.test.js index f815fb1..2c11d87 100644 --- a/src/replace.spec.test.js +++ b/src/replace.spec.test.js @@ -23,8 +23,8 @@ const defaults = { } let output, dir -{ - const dirObj = tmp.dirSync() // removing all files similar our tmp +{ // removing all files similar our tmp + const dirObj = tmp.dirSync() dir = dirObj.name glob.sync( @@ -170,10 +170,10 @@ tap.test('check api', async t => { ct.end() }) - await t.test('outputOptions as object', async ct => { + await t.test('outputWriteOptions as object', async ct => { testInput.content = content output = testInput.output = tmp.tmpNameSync({ prefix: tmpPrefixes.output, dir }) - testInput.outputOptions = { encoding: defaults.outputWriteOptions } + testInput.outputWriteOptions = { encoding: defaults.outputWriteOptions } await checkSyncAsync(ct, 'is', [testInput, expectedOutput, 'replaced correctly'])