├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── appveyor.yml
├── composer.js
├── docs
└── why-use-pipeline
│ ├── README.md
│ ├── pipe-error.png
│ └── pump-error.png
├── index.js
├── lib
├── create-error.js
├── gulp-uglify-error.js
├── log.js
└── minify.js
├── package.json
└── test
├── composer.js
├── create-error.js
├── err.js
├── minify.js
├── null.js
├── sourcemap.js
└── streams.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | components
4 | coverage
5 | .nyc_output
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - '0.10'
5 | - '0.12'
6 | - '4'
7 | - '6'
8 | - '8'
9 | - '10'
10 | matrix:
11 | include:
12 | - node_js: 10
13 | script: npm run lint
14 | script:
15 | - node --throw-deprecation ./node_modules/.bin/tape test/*.js
16 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | As of version 2.0.0, the CHANGELOG is maintained on [GitHub Releases](https://github.com/terinjokes/gulp-uglify/releases).
2 |
3 | # Change Log
4 |
5 |
6 | ## [1.5.4](https://github.com/terinjokes/gulp-uglify/compare/v1.5.3...v1.5.4) (2016-06-22)
7 |
8 | ## 1.5.3
9 |
10 | - Updated UglifyJS to 2.6.2
11 |
12 | ## 1.5.2
13 |
14 | - Updated UglfiyJS to 2.6.1
15 |
16 | ## 1.5.0
17 |
18 | - Update UglifyJS to 2.6.0.
19 | - CI and dependencies chores.
20 | - Attempt to resolve issue #109 where "ghost" files would appear in generated sourcemaps.
21 |
22 | ## 1.4.2
23 |
24 | - Updated UglifyJS to 2.5.0.
25 | - CI and dependencies chores.
26 |
27 | ## 1.4.1
28 |
29 | - Detect if options is a non-Object and log a warning.
30 |
31 | Older versions of Node.js did not allow Strings to be passed to `Object.keys` leading to errors and confusion to users following certain tutorials.
32 |
33 | ## 1.4.0
34 |
35 | - Deprecated the `preserveComments` option of "some".
36 | - Added the `preserveComments` option of "license" that uses [`uglify-save-license`](https://github.com/shinnn/uglify-save-license).
37 |
38 | ## 1.3.0
39 |
40 | - Updated UglifyJS to 2.4.24.
41 | - Streams3 support via through2 dependency update.
42 |
43 | ## 1.2.0
44 |
45 | - Update dependencies, including UglifyJS to 2.4.19.
46 |
47 | ## 1.1.0
48 |
49 | - Fix sources path in source maps (thanks @floridoo)
50 | - Update UglifyJS to 2.4.16 (thanks @tschaub)
51 |
52 | ## 1.0.0
53 |
54 | - Handle cases where UglifyJS uses e.msg instead of e.message for error codes. Fixes #51.
55 | - Supplement UglifyJS’s source map merging with vinyl-sourcemap-apply to correct issues where `sources` and `sourcesContent` were different. Fixes #43.
56 | - Refactor option parsing and defaults, and calls to uglify-js, to reduce complexity of the main function.
57 | - Added tests for the previously forgotten `preserveComments` option.
58 | - Updated UglifyJS to 2.4.15.
59 | - Changed dependencies to explicit ranges to avoid `node-semver` issues.
60 |
61 | ## 0.3.2
62 |
63 | - Removed the PluginError factory wrapper
64 | - Removed test that was failing due to gulp-util issue.
65 | - Tests should end the streams they are writing to.
66 | - Update dependencies. Fixes #44. Fixes #42.
67 |
68 | ## 0.3.1
69 |
70 | - Fixed homepage URL in npm metadata
71 | - Removes UglifyJS-inserted sourceMappingURL comment [Fixes #39]
72 | - Don’t pass input source map to UglifyJS if there are no mappings
73 | - Added installation instructions
74 |
75 | ## 0.3.0
76 |
77 | - Removed support for old style source maps
78 | - Added support for gulp-sourcemap
79 | - Updated tape development dependency
80 | - Dropped support for Node 0.9
81 | - UglifyJS errors are no longer swallowed
82 |
83 | ## 0.2.1
84 |
85 | - Correct source map output
86 | - Remove `gulp` dependency by using `vinyl` in testing
87 | - Passthrough null files correctly
88 | - Report error if attempting to use a stream-backed file
89 |
90 | ## 0.2.0
91 |
92 | - Dropped support for Node versions less than 0.9
93 | - Switched to using Streams2
94 | - Add support for generating source maps
95 | - Add option for preserving comments
96 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2017 Terin Stock
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gulp-uglify [![][travis-shield-img]][travis-shield][![][appveyor-shield-img]][appveyor-shield][![][npm-dl-shield-img]][npm-shield][![][npm-v-shield-img]][npm-shield][![][coveralls-shield-img]][coveralls-shield]
2 |
3 | > Minify JavaScript with UglifyJS3.
4 |
5 | ## Installation
6 |
7 | Install package with NPM and add it to your development dependencies:
8 |
9 | `npm install --save-dev gulp-uglify`
10 |
11 | ## Usage
12 |
13 | ```javascript
14 | var gulp = require('gulp');
15 | var uglify = require('gulp-uglify');
16 | var pipeline = require('readable-stream').pipeline;
17 |
18 | gulp.task('compress', function () {
19 | return pipeline(
20 | gulp.src('lib/*.js'),
21 | uglify(),
22 | gulp.dest('dist')
23 | );
24 | });
25 | ```
26 |
27 | To help properly handle error conditions with Node streams, this project
28 | recommends the use of
29 | [`pipeline`](https://nodejs.org/docs/latest/api/stream.html#stream_stream_pipeline_streams_callback),
30 | from [`readable-stream`](https://github.com/nodejs/readable-stream).
31 |
32 | ## Options
33 |
34 | Most of the [minify options](https://github.com/mishoo/UglifyJS2#minify-options) from
35 | the UglifyJS API are supported. There are a few exceptions:
36 |
37 | 1. The `sourceMap` option must not be set, as it will be automatically configured
38 | based on your Gulp configuration. See the documentation for [Gulp sourcemaps][gulp-sm].
39 |
40 | [gulp-sm]: https://github.com/gulp-sourcemaps/gulp-sourcemaps#usage
41 |
42 | ## Errors
43 |
44 | `gulp-uglify` emits an 'error' event if it is unable to minify a specific file.
45 | The GulpUglifyError constructor is exported by this plugin for `instanceof` checks.
46 | It contains the following properties:
47 |
48 | - `fileName`: The full file path for the file being minified.
49 | - `cause`: The original UglifyJS error, if available.
50 |
51 | Most UglifyJS error messages have the following properties:
52 |
53 | - `message` (or `msg`)
54 | - `filename`
55 | - `line`
56 |
57 | To see useful error messages, see [Why Use Pipeline?](docs/why-use-pipeline/README.md#why-use-pipeline).
58 |
59 | ## Using a Different UglifyJS
60 |
61 | By default, `gulp-uglify` uses the version of UglifyJS installed as a dependency.
62 | It's possible to configure the use of a different version using the "composer" entry point.
63 |
64 | ```javascript
65 | var uglifyjs = require('uglify-js'); // can be a git checkout
66 | // or another module (such as `uglify-es` for ES6 support)
67 | var composer = require('gulp-uglify/composer');
68 | var pump = require('pump');
69 |
70 | var minify = composer(uglifyjs, console);
71 |
72 | gulp.task('compress', function (cb) {
73 | // the same options as described above
74 | var options = {};
75 |
76 | pump([
77 | gulp.src('lib/*.js'),
78 | minify(options),
79 | gulp.dest('dist')
80 | ],
81 | cb
82 | );
83 | });
84 | ```
85 |
86 | [travis-shield-img]: https://img.shields.io/travis/terinjokes/gulp-uglify/master.svg?label=Travis%20CI&style=flat-square
87 | [travis-shield]: https://travis-ci.org/terinjokes/gulp-uglify
88 | [appveyor-shield-img]: https://img.shields.io/appveyor/ci/terinjokes/gulp-uglify/master.svg?label=AppVeyor&style=flat-square
89 | [appveyor-shield]: https://ci.appveyor.com/project/terinjokes/gulp-uglify
90 | [npm-dl-shield-img]: https://img.shields.io/npm/dm/gulp-uglify.svg?style=flat-square
91 | [npm-shield]: https://yarnpkg.com/en/package/gulp-uglify
92 | [npm-v-shield-img]: https://img.shields.io/npm/v/gulp-uglify.svg?style=flat-square
93 | [coveralls-shield-img]: https://img.shields.io/coveralls/terinjokes/gulp-uglify/master.svg?style=flat-square
94 | [coveralls-shield]: https://coveralls.io/github/terinjokes/gulp-uglify
95 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: "0.10"
4 | - nodejs_version: "0.12"
5 | - nodejs_version: "4"
6 |
7 | install:
8 | - ps: Install-Product node $env:nodejs_version
9 | - npm install
10 |
11 | test_script:
12 | - node --version
13 | - npm --version
14 | - npm test
15 |
16 | build: off
17 |
18 | version: "{build}"
19 |
--------------------------------------------------------------------------------
/composer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var through = require('through2');
3 | var minify = require('./lib/minify');
4 |
5 | module.exports = function(uglify, logger) {
6 | return function(opts) {
7 | var minifier = minify(uglify, logger)(opts);
8 | return through.obj(function(file, encoding, callback) {
9 | var newFile = null;
10 | var err = null;
11 | try {
12 | newFile = minifier(file);
13 | } catch (e) {
14 | err = e;
15 | }
16 | callback(err, newFile);
17 | });
18 | };
19 | };
20 |
--------------------------------------------------------------------------------
/docs/why-use-pipeline/README.md:
--------------------------------------------------------------------------------
1 | # Why Use Pipeline?
2 |
3 | When using `pipe` from the Node.js streams, errors are not propagated forward
4 | through the piped streams, and source streams aren’t closed if a destination
5 | stream closed. The [`pipeline`][pipeline] method of the Streams API normalizes
6 | these problems, and properly propagates errors of substreams to the pipeline.
7 |
8 | ## A common gulpfile example
9 |
10 | A common pattern in gulp files is to simply return a Node.js stream, and expect
11 | the gulp tool to handle errors.
12 |
13 | ```javascript
14 | // example of a common gulpfile
15 | var gulp = require('gulp');
16 | var uglify = require('gulp-uglify');
17 |
18 | gulp.task('compress', function () {
19 | // returns a Node.js stream, but no handling of error messages
20 | return gulp.src('lib/*.js')
21 | .pipe(uglify())
22 | .pipe(gulp.dest('dist'));
23 | });
24 | ```
25 |
26 | 
27 |
28 | There’s an error in one of the JavaScript files, but that error message is the
29 | opposite of helpful. You want to know what file and line contains the error. So
30 | what is this mess?
31 |
32 | When there’s an error in a stream, the Node.js stream fire the 'error' event,
33 | but if there’s no handler for this event, it instead goes to the defined
34 | [uncaught exception][uncaughtException] handler. The default behavior of the
35 | uncaught exception handler is documented:
36 |
37 | > By default, Node.js handles such exceptions by printing the stack trace to
38 | > stderr and exiting.
39 |
40 | ## Handling the Errors
41 |
42 | Since allowing the errors to make it to the uncaught exception handler isn’t
43 | useful, we should handle the exceptions properly. Let’s give that a quick shot.
44 |
45 | ```javascript
46 | var gulp = require('gulp');
47 | var uglify = require('gulp-uglify');
48 |
49 | gulp.task('compress', function () {
50 | return gulp.src('lib/*.js')
51 | .pipe(uglify())
52 | .pipe(gulp.dest('dist'))
53 | .on('error', function(err) {
54 | console.error('Error in compress task', err.toString());
55 | });
56 | });
57 | ```
58 |
59 | Unfortunately, Node.js stream’s `pipe` function doesn’t forward errors through
60 | the chain, so this error handler only handles the errors given by
61 | `gulp.dest`. Instead we need to handle errors for each stream.
62 |
63 | ```javascript
64 | var gulp = require('gulp');
65 | var uglify = require('gulp-uglify');
66 |
67 | gulp.task('compress', function () {
68 | function createErrorHandler(name) {
69 | return function (err) {
70 | console.error('Error from ' + name + ' in compress task', err.toString());
71 | };
72 | }
73 |
74 | return gulp.src('lib/*.js')
75 | .on('error', createErrorHandler('gulp.src'))
76 | .pipe(uglify())
77 | .on('error', createErrorHandler('uglify'))
78 | .pipe(gulp.dest('dist'))
79 | .on('error', createErrorHandler('gulp.dest'));
80 | });
81 | ```
82 |
83 | This is a lot of complexity to add in each of your gulp tasks, and it’s easy to
84 | forget to do it. In addition, it’s still not perfect, as it doesn’t properly
85 | signal to gulp’s task system that the task has failed. We can fix this, and we
86 | can handle the other pesky issues with error propagations with streams, but it’s
87 | even more work!
88 |
89 | ## Using pipelines
90 |
91 | The [`pipeline`][pipeline] method is a cheat code of sorts. It’s a wrapper
92 | around the `pipe` functionality that handles these cases for you, so you can
93 | stop hacking on your gulpfiles, and get back to hacking new features into your
94 | app.
95 |
96 | ```javascript
97 | var gulp = require('gulp');
98 | var uglify = require('gulp-uglify');
99 | var pipeline = require('readable-stream').pipeline;
100 |
101 | gulp.task('compress', function () {
102 | return pipeline(
103 | gulp.src('lib/*.js'),
104 | uglify(),
105 | gulp.dest('dist')
106 | );
107 | });
108 | ```
109 |
110 | The pipeline method accepts variable number of streams, which it internally
111 | pipes together. It is careful to propagate errors and destroy streams properly.
112 | The gulp task system waits for the returned pipeline stream to end, just like
113 | before, but can now handle errors from the substreams properly.
114 |
115 | 
116 |
117 | Now it’s very clear what plugin the error was from, what the error actually was,
118 | and from what file and line number.
119 |
120 | [pipeline]: https://nodejs.org/api/stream.html#stream_stream_pipeline_streams_callback
121 | [uncaughtException]: https://nodejs.org/api/process.html#process_event_uncaughtexception
122 |
--------------------------------------------------------------------------------
/docs/why-use-pipeline/pipe-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/terinjokes/gulp-uglify/7b9a7adc6f097a26a984c6598f93e15e286b18e3/docs/why-use-pipeline/pipe-error.png
--------------------------------------------------------------------------------
/docs/why-use-pipeline/pump-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/terinjokes/gulp-uglify/7b9a7adc6f097a26a984c6598f93e15e286b18e3/docs/why-use-pipeline/pump-error.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var uglify = require('uglify-js');
3 | var compose = require('./composer');
4 | var GulpUglifyError = require('./lib/gulp-uglify-error');
5 | var logger = require('./lib/log');
6 |
7 | module.exports = function(opts) {
8 | return compose(
9 | uglify,
10 | logger
11 | )(opts);
12 | };
13 |
14 | module.exports.GulpUglifyError = GulpUglifyError;
15 |
--------------------------------------------------------------------------------
/lib/create-error.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var GulpUglifyError = require('./gulp-uglify-error');
3 |
4 | function createError(file, msg, cause) {
5 | var perr = new GulpUglifyError(msg, cause);
6 | perr.plugin = 'gulp-uglify';
7 | perr.fileName = file.path;
8 | perr.showStack = false;
9 | return perr;
10 | }
11 |
12 | module.exports = createError;
13 |
--------------------------------------------------------------------------------
/lib/gulp-uglify-error.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var makeErrorCause = require('make-error-cause');
3 |
4 | var gulpUglifyError = makeErrorCause('GulpUglifyError');
5 | gulpUglifyError.prototype.toString = function() {
6 | var cause = this.cause || {};
7 |
8 | return (
9 | makeErrorCause.BaseError.prototype.toString.call(this) +
10 | (this.fileName ? '\nFile: ' + this.fileName : '') +
11 | (cause.line ? '\nLine: ' + cause.line : '') +
12 | (cause.col ? '\nCol: ' + cause.col : '')
13 | );
14 | };
15 |
16 | module.exports = gulpUglifyError;
17 |
--------------------------------------------------------------------------------
/lib/log.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var hasLog = require('has-gulplog');
3 | var each = require('array-each');
4 |
5 | var levels = ['debug', 'info', 'warn', 'error'];
6 |
7 | each(levels, function(level) {
8 | module.exports[level] = function() {
9 | if (hasLog()) {
10 | var log = require('gulplog');
11 |
12 | log[level].apply(log, arguments);
13 | }
14 | };
15 | });
16 |
--------------------------------------------------------------------------------
/lib/minify.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var Buffer = require('safe-buffer').Buffer;
3 | var applySourceMap = require('vinyl-sourcemaps-apply');
4 | var isObject = require('isobject');
5 | var extend = require('extend-shallow');
6 | var createError = require('./create-error');
7 |
8 | module.exports = function(uglify, log) {
9 | function setup(opts) {
10 | if (opts && !isObject(opts)) {
11 | log.warn('gulp-uglify expects an object, non-object provided');
12 | opts = {};
13 | }
14 |
15 | return extend(
16 | {},
17 | {
18 | output: {}
19 | },
20 | opts
21 | );
22 | }
23 |
24 | return function(opts) {
25 | return function(file) {
26 | var options = setup(opts || {});
27 | var hasSourceMaps = Boolean(file.sourceMap);
28 |
29 | if (file.isNull()) {
30 | return file;
31 | }
32 |
33 | if (file.isStream()) {
34 | throw createError(file, 'Streaming not supported', null);
35 | }
36 |
37 | if (hasSourceMaps) {
38 | options.sourceMap = {
39 | filename: file.sourceMap.file,
40 | includeSources: true
41 | };
42 |
43 | // UglifyJS generates broken source maps if the input source map
44 | // does not contain mappings.
45 | if (file.sourceMap.mappings) {
46 | options.sourceMap.content = file.sourceMap;
47 | }
48 | }
49 |
50 | var fileMap = {};
51 | fileMap[file.relative] = String(file.contents);
52 |
53 | var mangled = uglify.minify(fileMap, options);
54 |
55 | if (!mangled || mangled.error) {
56 | throw createError(
57 | file,
58 | 'unable to minify JavaScript',
59 | mangled && mangled.error
60 | );
61 | }
62 |
63 | if (mangled.warnings) {
64 | mangled.warnings.forEach(function(warning) {
65 | log.warn('gulp-uglify [%s]: %s', file.relative, warning);
66 | });
67 | }
68 |
69 | file.contents = Buffer.from(mangled.code);
70 |
71 | if (hasSourceMaps) {
72 | var sourceMap = JSON.parse(mangled.map);
73 | applySourceMap(file, sourceMap);
74 | }
75 |
76 | return file;
77 | };
78 | };
79 | };
80 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-uglify",
3 | "description": "Minify files with UglifyJS.",
4 | "version": "3.0.2",
5 | "author": "Terin Stock ",
6 | "bugs": "https://github.com/terinjokes/gulp-uglify/issues",
7 | "dependencies": {
8 | "array-each": "^1.0.1",
9 | "extend-shallow": "^3.0.2",
10 | "gulplog": "^1.0.0",
11 | "has-gulplog": "^0.1.0",
12 | "isobject": "^3.0.1",
13 | "make-error-cause": "^1.1.1",
14 | "safe-buffer": "^5.1.2",
15 | "through2": "^2.0.0",
16 | "uglify-js": "^3.0.5",
17 | "vinyl-sourcemaps-apply": "^0.2.0"
18 | },
19 | "devDependencies": {
20 | "eslint": "^3.18.0",
21 | "eslint-config-prettier": "^2.1.0",
22 | "eslint-config-xo": "^0.18.1",
23 | "eslint-plugin-no-use-extend-native": "^0.3.12",
24 | "eslint-plugin-prettier": "^2.0.1",
25 | "eslint-plugin-unicorn": "^2.1.0",
26 | "power-assert": "^1.4.1",
27 | "prettier": "^1.1.0",
28 | "source-list-map": "^1.1.2",
29 | "tape": "^4.9.1",
30 | "tape-catch": "^1.0.6",
31 | "testdouble": "^2.1.2",
32 | "vinyl": "^2.0.0"
33 | },
34 | "homepage": "https://github.com/terinjokes/gulp-uglify/",
35 | "keywords": [
36 | "gulpplugin"
37 | ],
38 | "license": "MIT",
39 | "main": "index.js",
40 | "repository": "terinjokes/gulp-uglify",
41 | "eslintConfig": {
42 | "env": {
43 | "node": true
44 | },
45 | "extends": [
46 | "xo",
47 | "prettier"
48 | ],
49 | "plugins": [
50 | "unicorn",
51 | "no-use-extend-native",
52 | "prettier"
53 | ],
54 | "rules": {
55 | "prettier/prettier": [
56 | "error",
57 | {
58 | "printWidth": 80,
59 | "tabWidth": 2,
60 | "singleQuote": true,
61 | "trailingComma": "none",
62 | "bracketSpacing": false
63 | }
64 | ]
65 | }
66 | },
67 | "files": [
68 | "index.js",
69 | "composer.js",
70 | "lib/"
71 | ],
72 | "scripts": {
73 | "lint": "eslint *.js lib test",
74 | "test": "tape test/*.js"
75 | },
76 | "greenkeeper": {
77 | "ignore": [
78 | "gulp-sourcemaps"
79 | ]
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/test/composer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var test = require('tape-catch');
3 | var assert = require('assert');
4 | var Buffer = require('safe-buffer').Buffer;
5 | var Vinyl = require('vinyl');
6 | var td = require('testdouble');
7 | var through = require('through2');
8 | var composer = require('../composer');
9 | var GulpUglifyError = require('../lib/gulp-uglify-error');
10 |
11 | test('composer should forward errors', function(t) {
12 | var badJsFile = new Vinyl({
13 | cwd: '/',
14 | base: '/test/',
15 | path: '/test/file.js',
16 | contents: Buffer.from('invalid js')
17 | });
18 |
19 | var uglify = td.object(['minify']);
20 | var logger = td.object(['warn']);
21 | var composed = composer(uglify, logger)({});
22 |
23 | assert.throws(function() {
24 | composed.write(badJsFile);
25 | }, GulpUglifyError);
26 |
27 | td.reset();
28 | t.end();
29 | });
30 |
31 | test("compose doesn't invoke callback twice", function(t) {
32 | var expectedErr = new Error();
33 | var jsFile = new Vinyl({
34 | cwd: '/',
35 | base: '/test/',
36 | path: '/test/file.js',
37 | contents: Buffer.from('var x = 123')
38 | });
39 |
40 | var thrower = through.obj(function() {
41 | throw expectedErr;
42 | });
43 |
44 | var uglify = td.object(['minify']);
45 | var logger = td.object(['warn']);
46 | td.when(
47 | uglify.minify(
48 | {'file.js': 'var x = 123'},
49 | {
50 | output: {}
51 | }
52 | )
53 | ).thenReturn({
54 | code: '',
55 | map: {}
56 | });
57 |
58 | var composed = composer(uglify, logger)({});
59 | composed.pipe(thrower);
60 |
61 | assert.throws(
62 | function() {
63 | composed.write(jsFile);
64 | },
65 | function(err) {
66 | assert.strictEqual(err, expectedErr);
67 | return true;
68 | }
69 | );
70 |
71 | td.reset();
72 | t.end();
73 | });
74 |
--------------------------------------------------------------------------------
/test/create-error.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var test = require('tape-catch');
3 | var assert = require('assert');
4 | var Buffer = require('safe-buffer').Buffer;
5 | var Vinyl = require('vinyl');
6 | var createError = require('../lib/create-error');
7 | var GulpUglifyError = require('../lib/gulp-uglify-error');
8 |
9 | test('createError has error message', function(t) {
10 | var e = createError(createTestFile(), 'error message text', null);
11 |
12 | assert.ok(e instanceof Error, 'argument should be of type Error');
13 | assert.ok(
14 | e instanceof GulpUglifyError,
15 | 'argument should be of type GulpUglifyError'
16 | );
17 | assert.equal(e.plugin, 'gulp-uglify', 'error is from gulp-uglify');
18 | assert.equal(e.message, 'error message text');
19 | assert.ok(!e.cause, 'should not contain a cause');
20 |
21 | t.end();
22 | });
23 |
24 | test('createError wraps cause', function(t) {
25 | var cause = new Error('boom!');
26 | var e = createError(createTestFile(), 'error message text', cause);
27 |
28 | assert.ok(e instanceof Error, 'argument should be of type Error');
29 | assert.ok(
30 | e instanceof GulpUglifyError,
31 | 'argument should be of type GulpUglifyError'
32 | );
33 | assert.equal(e.plugin, 'gulp-uglify', 'error is from gulp-uglify');
34 | assert.ok(e.message.match(/^error message text/));
35 | assert.equal(e.cause, cause);
36 |
37 | t.end();
38 | });
39 |
40 | function createTestFile() {
41 | var testOkContentsInput =
42 | '"use strict"; (function(console, first, second) { console.log(first + second) }(5, 10))';
43 |
44 | return new Vinyl({
45 | cwd: '/home/terin/broken-promises/',
46 | base: '/home/terin/broken-promises/test',
47 | path: '/home/terin/broken-promises/test/test2.js',
48 | contents: Buffer.from(testOkContentsInput)
49 | });
50 | }
51 |
--------------------------------------------------------------------------------
/test/err.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var test = require('tape-catch');
3 | var assert = require('assert');
4 | var Buffer = require('safe-buffer').Buffer;
5 | var Vinyl = require('vinyl');
6 | var td = require('testdouble');
7 | var GulpUglifyError = require('../lib/gulp-uglify-error');
8 | var minify = require('../lib/minify');
9 |
10 | test('errors should report files in error', function(t) {
11 | var testFile = new Vinyl({
12 | cwd: '/home/terin/broken-promises/',
13 | base: '/home/terin/broken-promises/test',
14 | path: '/home/terin/broken-promises/test/test1.js',
15 | contents: Buffer.from('function errorFunction(error)\n{')
16 | });
17 | var uglify = td.object(['minify']);
18 | var logger = td.object(['warn']);
19 | var expOptions = {
20 | output: {}
21 | };
22 | var err = new Error();
23 | err.line = 28889;
24 |
25 | td.when(
26 | uglify.minify(
27 | {
28 | 'test1.js': 'function errorFunction(error)\n{'
29 | },
30 | expOptions
31 | )
32 | ).thenReturn({
33 | error: err
34 | });
35 |
36 | var subject = minify(uglify, logger)({});
37 |
38 | assert.throws(
39 | function() {
40 | subject(testFile);
41 | },
42 | function(err) {
43 | assert.ok(
44 | err instanceof GulpUglifyError,
45 | 'argument should be of type GulpUglifyError'
46 | );
47 | assert.equal(err.plugin, 'gulp-uglify', 'error is from gulp-uglify');
48 | assert.equal(
49 | err.fileName,
50 | testFile.path,
51 | 'error reports correct file name'
52 | );
53 | assert.equal(err.cause.line, 28889, 'error reports correct line number');
54 | assert.ok(err.stack, 'error has a stack');
55 | assert.ok(!err.showStack, 'error is configured to not print the stack');
56 | assert.ok(err instanceof Error, 'argument should be of type Error');
57 |
58 | return true;
59 | }
60 | );
61 |
62 | td.verify(logger.warn(), {times: 0, ignoreExtraArgs: true});
63 | td.reset();
64 | t.end();
65 | });
66 |
67 | test("errors shouldn't blow up", function(t) {
68 | var testFile = new Vinyl({
69 | cwd: '/home/terin/broken-promises/',
70 | base: '/home/terin/broken-promises/test',
71 | path: '/home/terin/broken-promises/test/test1.js',
72 | contents: Buffer.from('{}')
73 | });
74 | var uglify = td.object(['minify']);
75 | var logger = td.object(['warn']);
76 | var expOptions = {
77 | output: {
78 | exportAll: true
79 | }
80 | };
81 | var err = new Error('`exportAll` is not a supported option');
82 |
83 | td.when(
84 | uglify.minify(
85 | {
86 | 'test1.js': '{}'
87 | },
88 | expOptions
89 | )
90 | ).thenReturn({
91 | error: err
92 | });
93 |
94 | var subject = minify(uglify, logger)({
95 | output: {
96 | exportAll: true
97 | }
98 | });
99 |
100 | assert.throws(
101 | function() {
102 | subject(testFile);
103 | },
104 | function(err) {
105 | assert.ok(err instanceof Error, 'argument should be of type Error');
106 | assert.ok(
107 | err instanceof GulpUglifyError,
108 | 'argument should be of type GulpUglifyError'
109 | );
110 | assert.equal(err.cause.message, '`exportAll` is not a supported option');
111 | assert.equal(err.plugin, 'gulp-uglify', 'error is from gulp-uglify');
112 | assert.equal(
113 | err.fileName,
114 | testFile.path,
115 | 'error reports correct file name'
116 | );
117 | assert.ok(!err.showStack, 'error is configured to not print the stack');
118 |
119 | return true;
120 | }
121 | );
122 |
123 | td.verify(logger.warn(), {times: 0, ignoreExtraArgs: true});
124 | td.reset();
125 | t.end();
126 | });
127 |
--------------------------------------------------------------------------------
/test/minify.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var test = require('tape-catch');
3 | var assert = require('assert');
4 | var Vinyl = require('vinyl');
5 | var Buffer = require('safe-buffer').Buffer;
6 | var td = require('testdouble');
7 | var minify = require('../lib/minify');
8 |
9 | test('minify should work', function(t) {
10 | var testContentsInput =
11 | '"use strict"; (function(console, first, second) { console.log(first + second) }(5, 10))';
12 | var testFile = createTestFile(testContentsInput);
13 | var uglify = td.object(['minify']);
14 | var logger = td.object(['warn']);
15 |
16 | td.when(
17 | uglify.minify(
18 | {
19 | 'test1.js': testContentsInput
20 | },
21 | {
22 | output: {}
23 | }
24 | )
25 | ).thenReturn({
26 | code: 'foobar'
27 | });
28 |
29 | var subject = minify(uglify, logger)({});
30 | var file = subject(testFile);
31 |
32 | assert.ok(file instanceof Vinyl);
33 | assert.ok(Buffer.isBuffer(file.contents));
34 | assert.equal(String(file.contents), 'foobar');
35 |
36 | td.verify(logger.warn(), {
37 | times: 0,
38 | ignoreExtraArgs: true
39 | });
40 | td.reset();
41 | t.end();
42 | });
43 |
44 | test('minify should warn with string argument', function(t) {
45 | var testContentsInput =
46 | '"use strict"; (function(console, first, second) { console.log(first + second) }(5, 10))';
47 | var testFile = createTestFile(testContentsInput);
48 | var uglify = td.object(['minify']);
49 | var logger = td.object(['warn']);
50 |
51 | td.when(
52 | uglify.minify(
53 | {
54 | 'test1.js': testContentsInput
55 | },
56 | {
57 | output: {}
58 | }
59 | )
60 | ).thenReturn({
61 | code: 'foobar'
62 | });
63 |
64 | var subject = minify(uglify, logger)('build.min.js');
65 | var file = subject(testFile);
66 |
67 | td.verify(logger.warn('gulp-uglify expects an object, non-object provided'));
68 |
69 | assert.ok(file instanceof Vinyl);
70 | assert.ok(Buffer.isBuffer(file.contents));
71 | assert.equal(String(file.contents), 'foobar');
72 |
73 | td.reset();
74 | t.end();
75 | });
76 |
77 | function createTestFile(input) {
78 | return new Vinyl({
79 | cwd: '/home/terin/broken-promises/',
80 | base: '/home/terin/broken-promises/test',
81 | path: '/home/terin/broken-promises/test/test1.js',
82 | contents: Buffer.from(input)
83 | });
84 | }
85 |
--------------------------------------------------------------------------------
/test/null.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var test = require('tape-catch');
3 | var assert = require('assert');
4 | var Vinyl = require('vinyl');
5 | var td = require('testdouble');
6 | var minify = require('../lib/minify');
7 |
8 | test('null Vinyl should passthrough', function(t) {
9 | var testFile = new Vinyl({
10 | cwd: '/home/terin/broken-promises/',
11 | base: '/home/terin/broken-promises/test',
12 | path: '/home/terin/broken-promises/test/test1.js',
13 | contents: null
14 | });
15 | var uglify = td.object(['minify']);
16 | var logger = td.object(['warn']);
17 |
18 | var subject = minify(uglify, logger)({});
19 |
20 | var file = subject(testFile);
21 |
22 | assert.strictEqual(file, testFile);
23 |
24 | td.verify(logger.warn(), {times: 0, ignoreExtraArgs: true});
25 | td.verify(uglify.minify(), {times: 0, ignoreExtraArgs: true});
26 | td.reset();
27 | t.end();
28 | });
29 |
--------------------------------------------------------------------------------
/test/sourcemap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var test = require('tape-catch');
3 | var assert = require('assert');
4 | var Buffer = require('safe-buffer').Buffer;
5 | var Vinyl = require('vinyl');
6 | var SourceListMap = require('source-list-map').SourceListMap;
7 | var fromStringWithSourceMap = require('source-list-map')
8 | .fromStringWithSourceMap;
9 | var td = require('testdouble');
10 | var minify = require('../lib/minify');
11 |
12 | test('sourcemaps should be merged', function(t) {
13 | var testContents1Input =
14 | '(function(first, second) {\n console.log(first + second);\n}(5, 10));\n';
15 | var testFile = new Vinyl({
16 | cwd: '/home/terin/broken-promises/',
17 | base: '/home/terin/broken-promises/test',
18 | path: '/home/terin/broken-promises/test/test1.js',
19 | contents: Buffer.from(testContents1Input)
20 | });
21 |
22 | var originalMap = new SourceListMap();
23 | originalMap.add(testContents1Input, 'test1.js', testContents1Input);
24 | testFile.sourceMap = originalMap.toStringWithSourceMap({
25 | file: 'test1.js'
26 | }).map;
27 |
28 | var outMap = fromStringWithSourceMap(
29 | 'foobar',
30 | testFile.sourceMap
31 | ).toStringWithSourceMap({file: 'test1.js'});
32 |
33 | var uglify = td.object(['minify']);
34 | var logger = td.object(['logger']);
35 |
36 | td.when(
37 | uglify.minify(
38 | {
39 | 'test1.js': testContents1Input
40 | },
41 | {
42 | output: {},
43 | sourceMap: {
44 | filename: 'test1.js',
45 | includeSources: true,
46 | content: testFile.sourceMap
47 | }
48 | }
49 | )
50 | ).thenReturn({
51 | code: 'foobar',
52 | map: JSON.stringify(outMap.map)
53 | });
54 |
55 | var subject = minify(uglify, logger)({});
56 | var file = subject(testFile);
57 |
58 | assert.ok(file instanceof Vinyl);
59 | assert.ok(Buffer.isBuffer(file.contents), 'file contents are a buffer');
60 |
61 | assert.equal(String(file.contents), 'foobar');
62 |
63 | assert.ok(file.sourceMap, 'has a source map');
64 | assert.equal(file.sourceMap.version, 3, 'source map has expected version');
65 | assert.ok(
66 | Array.isArray(file.sourceMap.sources),
67 | 'source map has sources array'
68 | );
69 | assert.ok(Array.isArray(file.sourceMap.names), 'source maps has names array');
70 | assert.ok(file.sourceMap.mappings, 'source map has mappings');
71 | td.reset();
72 | t.end();
73 | });
74 |
75 | test('sourcemaps should merge when concatted', function(t) {
76 | var inMap = new SourceListMap();
77 | inMap.add('foo\n', 'foo.js', 'foo\n');
78 | inMap.add('bar\n', 'bar.js', 'bar\n');
79 |
80 | var testFile = new Vinyl({
81 | cwd: '/home/terin/broken-promises/',
82 | base: '/home/terin/broken-promises/test',
83 | path: '/home/terin/broken-promises/test/test1.js',
84 | contents: Buffer.from(String(inMap))
85 | });
86 | testFile.sourceMap = inMap.toStringWithSourceMap({file: 'test1.js'}).map;
87 |
88 | var outMap = new SourceListMap();
89 | outMap.add(' ', 'foo.js', 'foo\n');
90 | outMap.add(' ', 'bar.js', 'bar\n');
91 | outMap = outMap.toStringWithSourceMap({file: 'test1.js'});
92 |
93 | var uglify = td.object(['minify']);
94 | var logger = td.object(['warn']);
95 |
96 | td.when(
97 | uglify.minify(
98 | {
99 | 'test1.js': String(inMap)
100 | },
101 | {
102 | output: {},
103 | sourceMap: {
104 | filename: 'test1.js',
105 | includeSources: true,
106 | content: testFile.sourceMap
107 | }
108 | }
109 | )
110 | ).thenReturn({
111 | code: 'send a PR changing this to the best La Croix flavor',
112 | map: JSON.stringify(outMap.map)
113 | });
114 |
115 | var subject = minify(uglify, logger)({});
116 | var file = subject(testFile);
117 |
118 | assert.ok(file instanceof Vinyl);
119 | assert.ok(Buffer.isBuffer(file.contents), 'file contents are a buffer');
120 | assert.equal(
121 | String(file.contents),
122 | 'send a PR changing this to the best La Croix flavor'
123 | );
124 |
125 | assert.ok(file.sourceMap, 'has a source map');
126 | assert.equal(file.sourceMap.version, 3, 'source map has expected version');
127 | assert.ok(
128 | Array.isArray(file.sourceMap.sources),
129 | 'source map has sources array'
130 | );
131 | assert.deepEqual(
132 | file.sourceMap.sources,
133 | ['foo.js', 'bar.js'],
134 | 'sources array has the inputs'
135 | );
136 | assert.ok(Array.isArray(file.sourceMap.names), 'source maps has names array');
137 | assert.ok(file.sourceMap.mappings, 'source map has mappings');
138 | td.reset();
139 | t.end();
140 | });
141 |
--------------------------------------------------------------------------------
/test/streams.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var test = require('tape-catch');
3 | var assert = require('assert');
4 | var GulpUglifyError = require('../lib/gulp-uglify-error');
5 | var td = require('testdouble');
6 | var minify = require('../lib/minify');
7 |
8 | test('stream Vinyls should emit error', function(t) {
9 | var uglify = td.object(['minify']);
10 | var logger = td.object(['warn']);
11 | var file = td.object(['isNull', 'isStream']);
12 |
13 | var subject = minify(uglify, logger)({});
14 |
15 | td.when(file.isNull()).thenReturn(false);
16 | td.when(file.isStream()).thenReturn(true);
17 |
18 | assert.throws(function() {
19 | subject(file);
20 | }, GulpUglifyError);
21 | td.reset();
22 | t.end();
23 | });
24 |
--------------------------------------------------------------------------------