Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

copy-webpack-plugin

Package Overview
Dependencies
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

copy-webpack-plugin - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

CHANGELOG.md

120

index.js

@@ -11,40 +11,85 @@ var _ = require('lodash');

var baseDir = compiler.options.context;
var fileDependencies = [];
var contextDependencies = [];
var lastGlobalUpdate = 0;
compiler.plugin('emit', function(compilation, cb) {
Promise.each(patterns, function(pattern) {
var relSrc = pattern.from;
var absSrc = path.resolve(baseDir, relSrc);
var relDest = pattern.to || '';
var relSrc = pattern.from;
var absSrc = path.resolve(baseDir, relSrc);
var relDest = pattern.to || '';
var forceWrite = !!pattern.force;
return fs.statAsync(absSrc)
.then(function(stat) {
if (stat.isDirectory()) {
return writeDirectoryToAssets(compilation,
absSrc,
relDest);
return fs.statAsync(absSrc)
.then(function(stat) {
if (stat.isDirectory()) {
contextDependencies.push(absSrc);
return writeDirectoryToAssets({
compilation: compilation,
absDirSrc: absSrc,
relDirDest: relDest,
forceWrite: forceWrite,
lastGlobalUpdate: lastGlobalUpdate
});
} else {
fileDependencies.push(absSrc);
if ((path.extname(relDest) === '' || // doesn't have an extension
_.last(relDest) === '/' || // doesn't end in a slash
pattern.toType === 'dir') && // is explicitly a dir
pattern.toType !== 'file') { // is not explicitly a file
relDest = path.join(relDest, path.basename(relSrc));
} else {
if ((path.extname(relDest) === '' || // doesn't have an extension
_.last(relDest) === '/' || // doesn't end in a slash
pattern.toType === 'dir') && // is explicitly a dir
pattern.toType !== 'file') { // is not explicitly a file
relDest = path.join(relDest, path.basename(relSrc));
} else {
relDest = relDest || path.basename(relSrc);
}
return writeFileToAssets(compilation,
absSrc,
relDest);
relDest = relDest || path.basename(relSrc);
}
});
})
.catch(function(err) {
compilation.errors.push(err);
})
.finally(cb);
return writeFileToAssets({
compilation: compilation,
absFileSrc: absSrc,
relFileDest: relDest,
forceWrite: forceWrite,
lastGlobalUpdate: lastGlobalUpdate
});
}
});
})
.then(function() {
lastGlobalUpdate = _.now();
})
.catch(function(err) {
compilation.errors.push(err);
})
.finally(cb);
});
compiler.plugin("after-emit", function(compilation, cb) {
var trackedFiles = compilation.fileDependencies;
_.each(fileDependencies, function(file) {
if (!_.contains(trackedFiles, file)) {
trackedFiles.push(file);
}
});
var trackedDirs = compilation.contextDependencies;
_.each(contextDependencies, function(context) {
if (!_.contains(trackedDirs, context)) {
trackedDirs.push(context);
}
});
cb();
});
}
function writeFileToAssets(compilation, absFileSrc, relFileDest) {
function writeFileToAssets(opts) {
var compilation = opts.compilation;
var relFileDest = opts.relFileDest;
var absFileSrc = opts.absFileSrc;
var forceWrite = opts.forceWrite;
var lastGlobalUpdate = opts.lastGlobalUpdate;
if (compilation.assets[relFileDest] && !forceWrite) {
return Promise.resolve();
}
return fs.statAsync(absFileSrc)
.then(function(stat) {
.then(function(stat) {
if (stat.mtime.getTime() > lastGlobalUpdate) {
compilation.assets[relFileDest] = {

@@ -58,6 +103,13 @@ size: function() {

};
});
}
});
}
function writeDirectoryToAssets(compilation, absDirSrc, relDirDest) {
function writeDirectoryToAssets(opts) {
var compilation = opts.compilation;
var absDirSrc = opts.absDirSrc;
var relDirDest = opts.relDirDest;
var forceWrite = opts.forceWrite;
var lastGlobalUpdate = opts.lastGlobalUpdate;
return dir.filesAsync(absDirSrc)

@@ -73,3 +125,9 @@ .each(function(absFileSrc) {

return writeFileToAssets(compilation, absFileSrc, relFileDest);
return writeFileToAssets({
compilation: compilation,
absFileSrc: absFileSrc,
relFileDest: relFileDest,
forceWrite: forceWrite,
lastGlobalUpdate: lastGlobalUpdate
});
});

@@ -76,0 +134,0 @@ }

{
"name": "copy-webpack-plugin",
"version": "0.1.0",
"version": "0.2.0",
"description": "Copy files and directories in webpack",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -69,2 +69,7 @@ ## Copy Webpack Plugin

* Overwrite existing file. By default, assets that are staged by previous plugins aren't overwritten. Provide `force` to override this behavior.
{ from: 'path/to/file.txt', force: true }
{ from: 'path/to/directory', force: true }
### Testing

@@ -71,0 +76,0 @@

var expect = require('chai').expect;
var CopyWebpackPlugin = require('../index');
var path = require('path');
var _ = require('lodash');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var HELPER_DIR = path.join(__dirname, 'helpers');
function MockCompiler() {
this.options = {
context: path.join(__dirname, 'helpers')
context: HELPER_DIR
};

@@ -12,3 +18,10 @@ }

MockCompiler.prototype.plugin = function(type, fn) {
this.emitFn = fn;
switch(type) {
case 'emit':
this.emitFn = fn;
break;
case 'after-emit':
this.afterEmitFn = fn;
break;
}
};

@@ -19,29 +32,100 @@

// Ideally we pass in patterns and confirm the resulting assets
function run(patterns, expectedAssetKeys, done) {
var plugin = new CopyWebpackPlugin(patterns);
function run(opts) {
return new Promise(function(resolve, reject) {
var plugin = new CopyWebpackPlugin(opts.patterns);
// Get a mock compiler to pass to plugin.apply
// Get a mock compiler to pass to plugin.apply
var compiler = opts.compiler || new MockCompiler();
plugin.apply(compiler);
// Call the registered function with a mock compilation and callback
var compilation = _.extend({
errors: [],
assets: {},
fileDependencies: [],
contextDependencies: []
}, opts.compilation);
// Execute the functions in series
Promise.each([compiler.emitFn, compiler.afterEmitFn], function(fn) {
return new Promise(function(res, rej) {
try {
fn(compilation, res);
} catch(e) {
rej(e);
}
});
})
.then(function() {
if (compilation.errors.length > 0) {
throw compilation.errors[0];
}
resolve(compilation);
})
.catch(reject);
});
}
function runEmit(opts) {
return run(opts)
.then(function(compilation) {
if (opts.expectedAssetKeys && opts.expectedAssetKeys.length > 0) {
expect(compilation.assets).to.have.all.keys(opts.expectedAssetKeys);
} else {
expect(compilation.assets).to.be.empty;
}
});
}
function runForce(opts) {
opts.compilation = {
assets: {}
};
opts.compilation.assets[opts.existingAsset] = {
source: function() {
return 'existing';
}
};
return run(opts)
.then(function(compilation) {
var assetContent = compilation.assets[opts.existingAsset].source().toString();
expect(assetContent).to.equal(opts.expectedAssetContent);
});
}
function runChange(opts) {
// Create two test files
fs.writeFileSync(opts.newFileLoc1);
fs.writeFileSync(opts.newFileLoc2);
// Create a reference to the compiler
var compiler = new MockCompiler();
plugin.apply(compiler);
// Call the registered function with a mock compilation and callback
var compilation = {
errors: [],
assets: {}
assets: {},
fileDependencies: [],
contextDependencies: []
};
return run({
compiler: compiler,
patterns: opts.patterns
})
// mtime is only measured in whole seconds
.delay(1000)
.then(function() {
compiler.emitFn(compilation, function() {
// After the callback has been called, check the compilation assets
try {
if (expectedAssetKeys.length > 0) {
expect(compilation.assets).to.have.all.keys(expectedAssetKeys);
} else {
expect(compilation.assets).to.be.empty;
}
// Change a file
fs.appendFileSync(opts.newFileLoc1, 'extra');
expect(compilation.errors).to.be.empty;
done();
} catch(e) {
done(e);
}
// Trigger another compile
return new Promise(function(res, rej) {
compiler.emitFn(compilation, res);
});
})
.then(function() {
return compilation;
})
.finally(function() {
fs.unlinkSync(opts.newFileLoc1);
fs.unlinkSync(opts.newFileLoc2);
});

@@ -52,5 +136,8 @@ }

it('doesn\'t throw an error if no patterns are passed', function(done) {
run(undefined,
[],
done);
runEmit({
patterns: undefined,
expectedAssetKeys: []
})
.then(done)
.catch(done);
});

@@ -74,56 +161,128 @@

describe('with file in from', function() {
it('can move a file to the root directory', function(done) {
run([{ from: 'file.txt' }],
['file.txt'],
done);
runEmit({
patterns: [{ from: 'file.txt' }],
expectedAssetKeys: ['file.txt']
})
.then(done)
.catch(done);
});
it('can move a file to a new directory without a forward slash', function(done) {
run([{ from: 'file.txt', to: 'newdirectory' }],
['newdirectory/file.txt'],
done);
runEmit({
patterns: [{ from: 'file.txt', to: 'newdirectory' }],
expectedAssetKeys: ['newdirectory/file.txt']
})
.then(done)
.catch(done);
});
it('can move a file to a new directory with a forward slash', function(done) {
run([{ from: 'file.txt', to: 'newdirectory/' }],
['newdirectory/file.txt'],
done);
runEmit({
patterns: [{ from: 'file.txt', to: 'newdirectory/' }],
expectedAssetKeys: ['newdirectory/file.txt']
})
.then(done)
.catch(done);
});
it('can move a file to a new directory with an extension', function(done) {
run([{ from: 'file.txt', to: 'newdirectory.ext', toType: 'dir' }],
['newdirectory.ext/file.txt'],
done);
runEmit({
patterns: [{ from: 'file.txt', to: 'newdirectory.ext', toType: 'dir' }],
expectedAssetKeys: ['newdirectory.ext/file.txt']
})
.then(done)
.catch(done);
});
it('can move a file to a new directory with an extension and forward slash', function(done) {
run([{ from: 'file.txt', to: 'newdirectory.ext/' }],
['newdirectory.ext/file.txt'],
done);
runEmit({
patterns: [{ from: 'file.txt', to: 'newdirectory.ext/' }],
expectedAssetKeys: ['newdirectory.ext/file.txt']
})
.then(done)
.catch(done);
});
it('can move a file to a new file with a different name', function(done) {
run([{ from: 'file.txt', to: 'newname.txt' }],
['newname.txt'],
done);
runEmit({
patterns: [{ from: 'file.txt', to: 'newname.txt' }],
expectedAssetKeys: ['newname.txt']
})
.then(done)
.catch(done);
});
it('can move a file to a new file with no extension', function(done) {
run([{ from: 'file.txt', to: 'newname', toType: 'file' }],
['newname'],
done);
runEmit({
patterns: [{ from: 'file.txt', to: 'newname', toType: 'file' }],
expectedAssetKeys: ['newname']
})
.then(done)
.catch(done);
});
it('can move a nested file to the root directory', function(done) {
run([{ from: 'directory/directoryfile.txt' }],
['directoryfile.txt'],
done);
runEmit({
patterns: [{ from: 'directory/directoryfile.txt' }],
expectedAssetKeys: ['directoryfile.txt']
})
.then(done)
.catch(done);
});
it('can move a nested file to a new directory', function(done) {
run([{ from: 'directory/directoryfile.txt', to: 'newdirectory' }],
['newdirectory/directoryfile.txt'],
done);
runEmit({
patterns: [{ from: 'directory/directoryfile.txt', to: 'newdirectory' }],
expectedAssetKeys: ['newdirectory/directoryfile.txt']
})
.then(done)
.catch(done);
});
it('won\'t overwrite a file already in the compilation', function(done) {
runForce({
patterns: [{ from: 'file.txt' }],
existingAsset: 'file.txt',
expectedAssetContent: 'existing'
})
.then(done)
.catch(done);
});
it('can force overwrite of a file already in the compilation', function(done) {
runForce({
patterns: [{ from: 'file.txt', force: true }],
existingAsset: 'file.txt',
expectedAssetContent: 'new'
})
.then(done)
.catch(done);
});
it('adds the file to the watch list', function(done) {
run({
patterns: [{ from: 'file.txt' }]
})
.then(function(compilation) {
var absFrom = path.join(HELPER_DIR, 'file.txt');
expect(compilation.fileDependencies).to.have.members([absFrom]);
})
.then(done)
.catch(done);
});
it('only include files that have changed', function(done) {
runChange({
patterns: [{ from: 'tempfile1.txt' }, { from: 'tempfile2.txt' }],
newFileLoc1: path.join(HELPER_DIR, 'tempfile1.txt'),
newFileLoc2: path.join(HELPER_DIR, 'tempfile2.txt')
})
.then(function(compilation) {
expect(compilation.assets).to.have.key('tempfile1.txt');
expect(compilation.assets).not.to.have.key('tempfile2.txt');
})
.then(done)
.catch(done);
});
});

@@ -133,25 +292,83 @@

it('can move a directory\'s contents to the root directory', function(done) {
run([{ from: 'directory' }],
['directoryfile.txt', 'nested/nestedfile.txt'],
done);
runEmit({
patterns: [{ from: 'directory' }],
expectedAssetKeys: ['directoryfile.txt', 'nested/nestedfile.txt']
})
.then(done)
.catch(done);
});
it('can move a directory\'s contents to a new directory', function(done) {
run([{ from: 'directory', to: 'newdirectory' }],
['newdirectory/directoryfile.txt','newdirectory/nested/nestedfile.txt'],
done);
runEmit({
patterns: [{ from: 'directory', to: 'newdirectory' }],
expectedAssetKeys: ['newdirectory/directoryfile.txt','newdirectory/nested/nestedfile.txt']
})
.then(done)
.catch(done);
});
it('can move a nested directory\'s contents to the root directory', function(done) {
run([{ from: 'directory/nested' }],
['nestedfile.txt'],
done);
runEmit({
patterns: [{ from: 'directory/nested' }],
expectedAssetKeys: ['nestedfile.txt']
})
.then(done)
.catch(done);
});
it('can move a nested directory\'s contents to a new directory', function(done) {
run([{ from: 'directory/nested', to: 'newdirectory' }],
['newdirectory/nestedfile.txt'],
done);
runEmit({
patterns: [{ from: 'directory/nested', to: 'newdirectory' }],
expectedAssetKeys: ['newdirectory/nestedfile.txt']
})
.then(done)
.catch(done);
});
it('won\'t overwrite a file already in the compilation', function(done) {
runForce({
patterns: [{ from: 'directory' }],
existingAsset: 'directoryfile.txt',
expectedAssetContent: 'existing'
})
.then(done)
.catch(done);
});
it('can force overwrite of a file already in the compilation', function(done) {
runForce({
patterns: [{ from: 'directory', force: true }],
existingAsset: 'directoryfile.txt',
expectedAssetContent: 'new'
})
.then(done)
.catch(done);
});
it('adds the directory to the watch list', function(done) {
run({
patterns: [{ from: 'directory' }]
})
.then(function(compilation) {
var absFrom = path.join(HELPER_DIR, 'directory');
expect(compilation.contextDependencies).to.have.members([absFrom]);
})
.then(done)
.catch(done);
});
it('only include files that have changed', function(done) {
runChange({
patterns: [{ from: 'directory' }],
newFileLoc1: path.join(HELPER_DIR, 'directory', 'tempfile1.txt'),
newFileLoc2: path.join(HELPER_DIR, 'directory', 'tempfile2.txt')
})
.then(function(compilation) {
expect(compilation.assets).to.have.key('tempfile1.txt');
expect(compilation.assets).not.to.have.key('tempfile2.txt');
})
.then(done)
.catch(done);
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc