├── .gitattributes
├── test
├── .eslintrc.json
├── beautify.validate.js
├── helper.js
├── beautify.reporter.js
└── beautify.js
├── .editorconfig
├── .travis.yml
├── .eslintrc.json
├── LICENSE.md
├── .gitignore
├── package.json
├── CHANGELOG.md
├── index.js
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.js text eol=lf
3 | *.json text eol=lf
4 |
--------------------------------------------------------------------------------
/test/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "mocha": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | - "lts/*"
5 | - "node"
6 | cache:
7 | directories:
8 | - node_modules
9 | after_script:
10 | - npm run coveralls
11 | sudo: false
12 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb-base",
3 | "rules": {
4 | "max-len": [2, 160, 2, {
5 | "ignoreUrls": true,
6 | "ignoreComments": false
7 | }],
8 | "no-param-reassign": 0
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2016 Tarun Chaudhry <opensource@chaudhry.co>
4 | Copyright (c) 2016-2019 Simone Biassoni
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | __THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.__
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 | .env.test
60 |
61 | # parcel-bundler cache (https://parceljs.org/)
62 | .cache
63 |
64 | # next.js build output
65 | .next
66 |
67 | # nuxt.js build output
68 | .nuxt
69 |
70 | # vuepress build output
71 | .vuepress/dist
72 |
73 | # Serverless directories
74 | .serverless/
75 |
76 | # FuseBox cache
77 | .fusebox/
78 |
79 | # DynamoDB Local files
80 | .dynamodb/
81 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-jsbeautifier",
3 | "description": "js-beautify for Gulp",
4 | "version": "3.0.1",
5 | "homepage": "https://github.com/tarunc/gulp-jsbeautifier",
6 | "author": {
7 | "name": "Tarun Chaudhry",
8 | "url": "https://github.com/tarunc"
9 | },
10 | "contributors": [
11 | {
12 | "name": "Simone Biassoni",
13 | "url": "https://github.com/biasso"
14 | },
15 | {
16 | "name": "Denny Ayard",
17 | "url": "https://github.com/djayard"
18 | }
19 | ],
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/tarunc/gulp-jsbeautifier.git"
23 | },
24 | "bugs": {
25 | "url": "https://github.com/tarunc/gulp-jsbeautifier/issues"
26 | },
27 | "license": "MIT",
28 | "main": "index.js",
29 | "files": [
30 | "CHANGELOG.md",
31 | "LICENSE.md",
32 | "README.md",
33 | "index.js"
34 | ],
35 | "engines": {
36 | "node": ">=4"
37 | },
38 | "scripts": {
39 | "lint": "eslint . --ignore-path .gitignore",
40 | "test": "nyc --reporter=html --reporter=text mocha",
41 | "coveralls": "nyc report --reporter=text-lcov | coveralls"
42 | },
43 | "dependencies": {
44 | "ansi-colors": "^4.1.1",
45 | "cosmiconfig": "^5.2.1",
46 | "fancy-log": "^1.3.3",
47 | "js-beautify": "^1.10.1",
48 | "lodash.mergewith": "^4.6.2",
49 | "plugin-error": "^1.0.1",
50 | "through2": "^3.0.1"
51 | },
52 | "devDependencies": {
53 | "chai": "^4.2.0",
54 | "coveralls": "^3.0.5",
55 | "del": "^4.1.1",
56 | "eslint": "^5.16.0",
57 | "eslint-config-airbnb-base": "^13.2.0",
58 | "eslint-plugin-import": "^2.18.2",
59 | "mocha": "^6.2.0",
60 | "nyc": "^14.1.1",
61 | "sinon": "^7.3.2",
62 | "vinyl": "^2.2.0"
63 | },
64 | "keywords": [
65 | "beautifier",
66 | "beautify",
67 | "css",
68 | "format",
69 | "gulp",
70 | "gulpplugin",
71 | "html",
72 | "indent",
73 | "javascript",
74 | "js-beautify",
75 | "js",
76 | "jsbeautifier",
77 | "json",
78 | "prettify"
79 | ]
80 | }
81 |
--------------------------------------------------------------------------------
/test/beautify.validate.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const sinon = require('sinon');
3 | const beautify = require('../');
4 | const helper = require('./helper');
5 |
6 | describe('validate()', () => {
7 | beforeEach(() => {
8 | sinon.spy(process.stdout, 'write');
9 | });
10 |
11 | afterEach(() => {
12 | sinon.restore();
13 | });
14 |
15 | describe('with the default options', () => {
16 | helper.supportedFiles.forEach((file) => {
17 | it(`should not edit the content of not beautified'${file.name}'`, (done) => {
18 | const stream = beautify.validate();
19 | const vinylFile = helper.createFile(file.name, helper.defaultContents[file.type].actual);
20 |
21 | stream.on('error', done);
22 | stream.on('data', (newFile) => {
23 | assert.strictEqual(newFile.contents.toString(), helper.defaultContents[file.type].actual);
24 | assert.strictEqual(newFile.jsbeautify.beautified, false);
25 | assert.strictEqual(newFile.jsbeautify.canBeautify, true);
26 | assert.strictEqual(newFile.jsbeautify.type, file.type);
27 | sinon.assert.notCalled(process.stdout.write);
28 | done();
29 | });
30 | stream.write(vinylFile);
31 | });
32 | });
33 |
34 | helper.supportedFiles.forEach((file) => {
35 | it(`should not edit the content of beautified'${file.name}'`, (done) => {
36 | const stream = beautify.validate();
37 | const vinylFile = helper.createFile(file.name, helper.defaultContents[file.type].expected);
38 |
39 | stream.on('error', done);
40 | stream.on('data', (newFile) => {
41 | assert.strictEqual(newFile.contents.toString(), helper.defaultContents[file.type].expected);
42 | assert.strictEqual(newFile.jsbeautify.beautified, false);
43 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
44 | assert.strictEqual(newFile.jsbeautify.type, file.type);
45 | sinon.assert.notCalled(process.stdout.write);
46 | done();
47 | });
48 | stream.write(vinylFile);
49 | });
50 | });
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/test/helper.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const Vinyl = require('vinyl');
3 |
4 | exports.createFile = (filename, contents) => {
5 | const base = path.join(__dirname, 'fixtures');
6 | const filePath = path.join(base, filename);
7 |
8 | const file = new Vinyl({
9 | cwd: __dirname,
10 | path: filePath,
11 | base,
12 | contents: typeof contents === 'string' ? Buffer.from(contents) : contents,
13 | });
14 |
15 | return file;
16 | };
17 |
18 | exports.defaultContents = {
19 | css: {
20 | actual: '#foo.bar{height:100px;width:100px;}',
21 | expected: '#foo.bar {\n height: 100px;\n width: 100px;\n}',
22 | },
23 | html: {
24 | actual: '
',
25 | expected: '\n\n\n\n \n\n\n\n\n',
26 | },
27 | js: {
28 | actual: 'var foo={bar:1,baz:2};',
29 | expected: 'var foo = {\n bar: 1,\n baz: 2\n};',
30 | },
31 | };
32 |
33 | exports.customContents = {
34 | css: {
35 | actual: '#foo.bar{height:100px;width:100px;}',
36 | expected: '#foo.bar {\n height: 100px;\n width: 100px;\n}',
37 | },
38 | html: {
39 | actual: '',
40 | expected: '\n\n\n\n\t\n\n\n\n\n',
41 | },
42 | js: {
43 | actual: 'var foo={bar:1,baz:2};',
44 | expected: 'var foo = {\n bar: 1,\n baz: 2\n};',
45 | },
46 | };
47 |
48 | exports.customOptions = {
49 | indent_char: ' ',
50 | indent_size: 2,
51 | css: {
52 | indent_size: 1,
53 | },
54 | html: {
55 | indent_char: '\t',
56 | indent_size: 1,
57 | },
58 | };
59 |
60 | exports.supportedFiles = [{
61 | name: 'file.css',
62 | type: 'css',
63 | }, {
64 | name: 'file.html',
65 | type: 'html',
66 | }, {
67 | name: 'file.js',
68 | type: 'js',
69 | }];
70 |
71 | exports.notSupportedFiles = [{
72 | name: 'file.css.erb',
73 | type: 'css',
74 | }, {
75 | name: 'file.html.erb',
76 | type: 'html',
77 | }, {
78 | name: 'file.js.erb',
79 | type: 'js',
80 | }];
81 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 3.0.1 - 2019-07-25
4 | - Update dependencies
5 |
6 | ## 3.0.0 - 2018-12-29
7 | - Drop support for node <6
8 | - Add support to YAML configuration file
9 | - Change the logic to merge options
10 | - Update dependencies
11 |
12 | ## 2.1.2 - 2018-01-01
13 | - Update dependencies
14 |
15 | ## 2.1.1 - 2017-06-11
16 | - Update dependencies
17 | - Correct documentation ([#29](https://github.com/tarunc/gulp-jsbeautifier/issues/29))
18 |
19 | ## 2.1.0 - 2017-03-08
20 | - Add validate function
21 | - Add `verbosity` option for reporter
22 | - Update copyright
23 |
24 | ## 2.0.4 - 2016-12-30
25 | - Update dependencies
26 |
27 | ## 2.0.3 - 2016-04-03
28 | - Improve documentation
29 | - Run lint before tests
30 | - Keep unnecessary files outside of the package
31 |
32 | ## 2.0.2 - 2016-03-03
33 | - Add tests for `debug` option
34 | - Fix some errors that could occur with the reporter
35 |
36 | ## 2.0.1 - 2016-03-02
37 | - Code refactoring
38 | - Improve tests
39 | - Fix an issue with file path ([#22](https://github.com/tarunc/gulp-jsbeautifier/issues/22), [#23](https://github.com/tarunc/gulp-jsbeautifier/issues/23))
40 |
41 | ## 2.0.0 - 2016-03-01
42 | - Total rewrite of gulp-jsbeautifier
43 | - Improve documentation
44 | - Improve tests
45 | - Add a reporter (replace `showDiff` option)
46 | - Add `debug` option
47 | - Remove `mode` and `showDiff` options (use `gulp-diff` package instead)
48 | - Change logic of merging options
49 | - Use 'snake_case' instead of 'camelCase' for options (for consistency with `js-beautify`)
50 |
51 | ## 1.0.2 - 2016-02-11
52 | - Added different color to the logs
53 | - Upgraded dependencies
54 |
55 | ## 1.0.1 - 2015-07-11
56 | - Added `showDiff` option
57 | - Upgrade `jsbeautifier` package
58 |
59 | ## 1.0.0 - 2015-06-19
60 | - Pushed out `1.0.0` release
61 |
62 | ## 0.0.8 - 2015-03-23
63 | - Fixed and added tests for `logSuccess` option
64 |
65 | ## 0.0.7 - 2015-03-19
66 | - Fixed option parsing to accept raw options
67 |
68 | ## 0.0.6 - 2015-03-11
69 | - Added `logSuccess` option
70 |
71 | ## 0.0.5 - 2015-03-06
72 | - Print out diff through `ansidiff`
73 |
74 | ## 0.0.4 - 2014-11-20
75 | - Allow for other versions of `jsbeautifier`
76 |
77 | ## 0.0.3 - 2014-10-01
78 | - Upgrade `jsbeautifier` package
79 |
80 | ## 0.0.2 - 2014-05-01
81 | - Added option to set `config: true` to default '.jsbeautifyrc'
82 |
83 | ## 0.0.1 - 2014-04-30
84 | - Initial release
85 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const beautify = require('js-beautify');
2 | const colors = require('ansi-colors');
3 | const cosmiconfig = require('cosmiconfig');
4 | const log = require('fancy-log');
5 | const mergeWith = require('lodash.mergewith');
6 | const path = require('path');
7 | const PluginError = require('plugin-error');
8 | const through = require('through2');
9 |
10 | const PLUGIN_NAME = 'gulp-jsbeautifier';
11 |
12 | /**
13 | * Merge options from different sources
14 | * @param {Object} pluginOptions The gulp-jsbeautifier options
15 | * @return {Object} The options
16 | */
17 | function mergeOptions(pluginOptions) {
18 | const defaultOptions = {
19 | config: null,
20 | debug: false,
21 | css: {
22 | file_types: ['.css', '.less', '.sass', '.scss'],
23 | },
24 | html: {
25 | file_types: ['.html'],
26 | },
27 | js: {
28 | file_types: ['.js', '.json'],
29 | },
30 | };
31 |
32 | // Load 'file options'
33 | const explorer = cosmiconfig('jsbeautify');
34 | let explorerResult;
35 |
36 | if (pluginOptions && pluginOptions.config) {
37 | explorerResult = explorer.loadSync(path.resolve(pluginOptions.config));
38 | } else {
39 | explorerResult = explorer.searchSync();
40 | }
41 |
42 | let fileOptions;
43 | if (explorerResult) {
44 | fileOptions = explorerResult.config;
45 | }
46 |
47 | // Merge options
48 | const finalOptions = mergeWith({}, defaultOptions, fileOptions, pluginOptions, (objValue, srcValue) => {
49 | if (Array.isArray(objValue)) {
50 | return objValue.concat(srcValue);
51 | }
52 |
53 | return undefined;
54 | });
55 |
56 | // Show debug messages
57 | if (finalOptions.debug) {
58 | if (fileOptions) {
59 | log(`File options:\n${JSON.stringify(fileOptions, null, 2)}`);
60 | }
61 |
62 | log(`Final options:\n${JSON.stringify(finalOptions, null, 2)}`);
63 | }
64 |
65 | // Delete properties not used
66 | delete finalOptions.config;
67 | delete finalOptions.debug;
68 |
69 | return finalOptions;
70 | }
71 |
72 | /**
73 | * Beautify files or perform validation
74 | * @param {Object} pluginOptions The gulp-jsbeautifier parameter options
75 | * @param {boolean} doValidation Specifies whether perform validation only
76 | * @return {Object} The object stream
77 | */
78 | function helper(pluginOptions, doValidation) {
79 | const options = mergeOptions(pluginOptions);
80 |
81 | return through.obj((file, encoding, callback) => {
82 | let oldContent;
83 | let newContent;
84 | let type = null;
85 |
86 | if (file.isNull()) {
87 | callback(null, file);
88 | return;
89 | }
90 |
91 | if (file.isStream()) {
92 | callback(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
93 | return;
94 | }
95 |
96 | // Check if current file should be treated as JavaScript, HTML, CSS or if it should be ignored
97 | ['js', 'css', 'html'].some((value) => {
98 | // Check if at least one element in 'file_types' is suffix of file basename
99 | if (options[value].file_types.some(suffix => path.basename(file.path).endsWith(suffix))) {
100 | type = value;
101 | return true;
102 | }
103 |
104 | return false;
105 | });
106 |
107 | // Initialize properties for reporter
108 | file.jsbeautify = {};
109 | file.jsbeautify.type = type;
110 | file.jsbeautify.beautified = false;
111 | file.jsbeautify.canBeautify = false;
112 |
113 | if (type) {
114 | oldContent = file.contents.toString('utf8');
115 | newContent = beautify[type](oldContent, options);
116 |
117 | if (oldContent.toString() !== newContent.toString()) {
118 | if (doValidation) {
119 | file.jsbeautify.canBeautify = true;
120 | } else {
121 | file.contents = Buffer.from(newContent);
122 | file.jsbeautify.beautified = true;
123 | }
124 | }
125 | }
126 |
127 | callback(null, file);
128 | });
129 | }
130 |
131 | /**
132 | * Beautify files
133 | * @param {Object} options The gulp-jsbeautifier parameter options
134 | * @return {Object} The object stream with beautified files
135 | */
136 | const plugin = options => helper(options, false);
137 |
138 | /**
139 | * Perform the validation of files without changing their content
140 | * @param {Object} options The gulp-jsbeautifier parameter options
141 | * @return {Object} The object stream
142 | */
143 | plugin.validate = options => helper(options, true);
144 |
145 | /**
146 | * Show results of beautification or validation
147 | * @param {Object} options The gulp-jsbeautifier reporter options
148 | * @return {Object} The object stream
149 | */
150 | plugin.reporter = (options) => {
151 | let verbosity = 0;
152 | let errorCount = 0;
153 |
154 | if (typeof options === 'object' && Object.prototype.hasOwnProperty.call(options, 'verbosity')) {
155 | ({ verbosity } = options);
156 | }
157 |
158 | return through.obj((file, encoding, callback) => {
159 | if (file.jsbeautify) {
160 | if (verbosity >= 1 && file.jsbeautify.type === null) {
161 | log(`Can not beautify ${colors.cyan(file.relative)}`);
162 | } else if (verbosity >= 0 && file.jsbeautify.beautified) {
163 | log(`Beautified ${colors.cyan(file.relative)} [${file.jsbeautify.type}]`);
164 | } else if (verbosity >= 0 && file.jsbeautify.canBeautify) {
165 | errorCount += 1;
166 | log(`Can beautify ${colors.cyan(file.relative)} [${file.jsbeautify.type}]`);
167 | } else if (verbosity >= 1) {
168 | log(`Already beautified ${colors.cyan(file.relative)} [${file.jsbeautify.type}]`);
169 | }
170 | }
171 |
172 | callback(null, file);
173 | }, function flush(callback) {
174 | if (errorCount > 0) {
175 | this.emit('error', new PluginError(PLUGIN_NAME, 'Validation not passed. Please beautify.'));
176 | }
177 | callback();
178 | });
179 | };
180 |
181 | plugin.report = {
182 | BEAUTIFIED: 0,
183 | ALL: 1,
184 | };
185 |
186 | module.exports = plugin;
187 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gulp-jsbeautifier
2 |
3 | [](https://travis-ci.org/tarunc/gulp-jsbeautifier)
4 | [](https://badge.fury.io/js/gulp-jsbeautifier)
5 | [](https://coveralls.io/github/tarunc/gulp-jsbeautifier?branch=master)
6 | [](https://codeclimate.com/github/tarunc/gulp-jsbeautifier)
7 | [](https://david-dm.org/tarunc/gulp-jsbeautifier)
8 | [](https://david-dm.org/tarunc/gulp-jsbeautifier#info=devDependencies)
9 |
10 | > Beautifier for JavaScript, JSON, HTML and CSS.\
11 | [js-beautify](https://beautifier.io/) for gulp.
12 |
13 | ## Install
14 |
15 | ```sh
16 | npm install --save-dev gulp-jsbeautifier
17 | ```
18 |
19 | ## Basic Usage
20 |
21 | ```javascript
22 | const gulp = require('gulp');
23 | const beautify = require('gulp-jsbeautifier');
24 |
25 | gulp.task('beautify', () =>
26 | gulp.src(['./*.css', './*.html', './*.js'])
27 | .pipe(beautify())
28 | .pipe(gulp.dest('./dist'))
29 | );
30 | ```
31 |
32 | ## Options
33 |
34 | All options are optional.
35 |
36 | ### Plugin options
37 |
38 | #### `css`, `html`, `js`
39 |
40 | Type: `Object`\
41 | Default value: `{ file_types: [...] }`
42 |
43 | Contains specific _[beautifier options](#beautifier-options)_ for CSS, HTML and JavaScript.
44 |
45 | * **`file_types`**\
46 | Type: `Array`\
47 | Default value for `css`: `['.css', '.less', '.sass', '.scss']`\
48 | Default value for `html`: `['.html']`\
49 | Default value for `js`: `['.js', '.json']`
50 |
51 | Specifies which files should be treated as CSS, HTML or JavaScript.
52 |
53 | ```javascript
54 | // In addition to the default file_types, the '.eslintrc' file is also considered as JavaScript.
55 | gulp.task('beautify', () =>
56 | gulp.src(['./*.js', './*.json', './.eslintrc'])
57 | .pipe(beautify({
58 | js: {
59 | file_types: ['.eslintrc']
60 | }
61 | }))
62 | .pipe(gulp.dest('./dist'))
63 | );
64 | ```
65 |
66 | #### `config`
67 |
68 | Type: `String`
69 | Default value: `null`
70 |
71 | If you provide a path to a configuration file, the options defined in it will be loaded.\
72 | Otherwise, a configuration file will be automatically searched as explained in [cosmiconfig docs](https://github.com/davidtheclark/cosmiconfig#cosmiconfig).
73 |
74 | The configuration file must be a valid JSON or YAML and can contain all the options of this documentation except `config` (it will be ignored).
75 |
76 | ```javascript
77 | // Use options loaded from './config/jsbeautify.json'.
78 | gulp.task('beautify', () =>
79 | gulp.src('./*.js')
80 | .pipe(beautify({
81 | config: './config/jsbeautify.json'
82 | }))
83 | .pipe(gulp.dest('./dist'))
84 | );
85 |
86 | // Use options automatically loaded from './jsbeautifyrc'.
87 | gulp.task('beautify', () =>
88 | gulp.src('./*.js')
89 | .pipe(beautify())
90 | .pipe(gulp.dest('./dist'))
91 | );
92 | ```
93 |
94 | #### `debug`
95 |
96 | Type: `Boolean`\
97 | Default value: `false`
98 |
99 | If `true` lists the options loaded from the configuration file and the final ones.\
100 | if you encounter any problems with the options try to enable it and use the [reporter](#reporter).
101 |
102 | ```javascript
103 | // Shows debug messages.
104 | gulp.task('beautify', () =>
105 | gulp.src(['./*.css', './*.html', './*.js'])
106 | .pipe(beautify({
107 | debug: true
108 | }))
109 | .pipe(gulp.dest('./dist'))
110 | );
111 | ```
112 |
113 | ### Beautifier options
114 |
115 | The _beautifier options_ are the same underscored options used by js-beautify and use the same setting inheritance.\
116 | See the [js-beautify docs](https://github.com/beautify-web/js-beautify) for a list of them.
117 |
118 | ```javascript
119 | // The indentation is 4 spaces for CSS and HTML, it's 1 tab for JavaScript.
120 | gulp.task('beautify', () =>
121 | gulp.src(['./*.css', './*.html', './*.js'])
122 | .pipe(beautify({
123 | indent_size: 4,
124 | js: {
125 | indent_char: '\t',
126 | indent_size: 1
127 | }
128 | }))
129 | .pipe(gulp.dest('./dist'))
130 | );
131 | ```
132 |
133 | The options provided as a parameter in gulp will be merged with those in the configuration file.\
134 | The merge order is: default values, configuration file, parameters.\
135 | Subsequent options overwrite the previous ones.
136 |
137 | ```javascript
138 | // 'config.json'
139 | // 4 spaces indentation for CSS and HTML.
140 | // 1 tab indentation for JavaScript.
141 | {
142 | "indent_char": " ",
143 | "indent_size": 4,
144 | "js": {
145 | "indent_char": "\t",
146 | "indent_size": 1
147 | }
148 | }
149 |
150 | // Overwrite the indentation defined in 'config.json' with 2 tab for CSS and HTML.
151 | // JavaScript files continue to mantain 1 tab indentation.
152 | gulp.task('beautify', () =>
153 | gulp.src(['./*.css', './*.html', './*.js'])
154 | .pipe(beautify({
155 | config: './config.json',
156 | indent_char: '\t',
157 | indent_size: 2
158 | }))
159 | .pipe(gulp.dest('./dist'))
160 | );
161 |
162 | // Options resulting after merge (only the relevant parts).
163 | {
164 | "indent_char": "\t",
165 | "indent_size": 2,
166 | "js": {
167 | "indent_char": "\t",
168 | "indent_size": 1
169 | }
170 | }
171 | ```
172 |
173 | ## Validate
174 |
175 | Checks if it is possible to beautify some files.\
176 | The reporter is responsible for displaying the validate results and will emit an error before
177 | the stream ends if a file could be beautified.
178 |
179 | ```javascript
180 | var gulp = require('gulp');
181 | var beautify = require('gulp-jsbeautifier');
182 |
183 | gulp.task('beautify', () =>
184 | gulp.src(['./*.css', './*.html', './*.js'])
185 | .pipe(beautify.validate())
186 | .pipe(beautify.reporter())
187 | );
188 | ```
189 |
190 | ## Reporter
191 |
192 | Lists files that have been beautified, those already beautified, and those that can not be beautified.\
193 | If the [validate](#validate) feature is used, the reporter lists files that can be beautified and emits an error before the stream ends if such a file was detected.
194 |
195 | ```javascript
196 | var gulp = require('gulp');
197 | var beautify = require('gulp-jsbeautifier');
198 |
199 | gulp.task('beautify', () =>
200 | gulp.src(['./*.css', './*.html', './*.js'])
201 | .pipe(beautify())
202 | .pipe(beautify.reporter())
203 | .pipe(gulp.dest('./dist'))
204 | );
205 | ```
206 |
207 | ### Reporter options
208 |
209 | #### `verbosity`
210 |
211 | Type: `number`\
212 | Default value: `beautify.report.BEAUTIFIED`\
213 | Other values: `beautify.report.ALL`
214 |
215 | With _BEAUTIFIED_ value, the reporter lists only beautified files (or those that can be beautified in the case of validate).
216 | With _ALL_ value, the reporter also lists the other files.
217 |
218 | ```javascript
219 | var gulp = require('gulp');
220 | var beautify = require('gulp-jsbeautifier');
221 |
222 | gulp.task('beautify', () =>
223 | gulp.src(['./*.css', './*.html', './*.js'])
224 | .pipe(beautify())
225 | .pipe(beautify.reporter({
226 | verbosity: beautify.report.ALL
227 | }))
228 | .pipe(gulp.dest('./dist'))
229 | );
230 | ```
231 |
232 | ## License
233 |
234 | `gulp-jsbeautifier` is released under the [MIT License](./LICENSE.md).
235 |
--------------------------------------------------------------------------------
/test/beautify.reporter.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const colors = require('ansi-colors');
3 | const sinon = require('sinon');
4 | const beautify = require('../');
5 | const helper = require('./helper');
6 |
7 | describe('reporter()', () => {
8 | beforeEach(() => {
9 | sinon.spy(process.stdout, 'write');
10 | });
11 |
12 | afterEach(() => {
13 | sinon.restore();
14 | });
15 |
16 | it('should not report anything if beautify() has not been called', (done) => {
17 | const stream = beautify.reporter();
18 | const vinylFile = helper.createFile('file.js', '');
19 |
20 | stream.on('error', done);
21 | stream.on('data', (newFile) => {
22 | assert.strictEqual(newFile.contents.toString(), '');
23 | assert.strictEqual(newFile.jsbeautify, undefined);
24 | assert(process.stdout.write.notCalled);
25 | done();
26 | });
27 | stream.write(vinylFile);
28 | });
29 |
30 | it('should report which files have been beautified with log verbosity set to ALL.', (done) => {
31 | const stream = beautify.reporter({
32 | verbosity: beautify.report.ALL,
33 | });
34 | const vinylFile = helper.createFile('file.js', '');
35 | vinylFile.jsbeautify = {
36 | beautified: true,
37 | canBeautify: false,
38 | type: 'js',
39 | };
40 |
41 | stream.on('error', done);
42 | stream.on('data', (newFile) => {
43 | assert.strictEqual(newFile.contents.toString(), '');
44 | assert.strictEqual(newFile.jsbeautify.beautified, true);
45 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
46 | assert.strictEqual(newFile.jsbeautify.type, 'js');
47 | assert.strictEqual(process.stdout.write.getCall(1).args[0], `Beautified ${colors.cyan('file.js')} [js]\n`);
48 | done();
49 | });
50 | stream.write(vinylFile);
51 | });
52 |
53 | it('should report which files have been beautified without specify log verbosity', (done) => {
54 | const stream = beautify.reporter();
55 | const vinylFile = helper.createFile('file.js', '');
56 | vinylFile.jsbeautify = {
57 | beautified: true,
58 | canBeautify: false,
59 | type: 'js',
60 | };
61 |
62 | stream.on('error', done);
63 | stream.on('data', (newFile) => {
64 | assert.strictEqual(newFile.contents.toString(), '');
65 | assert.strictEqual(newFile.jsbeautify.beautified, true);
66 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
67 | assert.strictEqual(newFile.jsbeautify.type, 'js');
68 | assert.strictEqual(process.stdout.write.getCall(1).args[0], `Beautified ${colors.cyan('file.js')} [js]\n`);
69 | done();
70 | });
71 | stream.write(vinylFile);
72 | });
73 |
74 | it('should report which files are already beautified with log verbosity set to ALL', (done) => {
75 | const stream = beautify.reporter({
76 | verbosity: beautify.report.ALL,
77 | });
78 | const vinylFile = helper.createFile('file.js', '');
79 | vinylFile.jsbeautify = {
80 | beautified: false,
81 | canBeautify: false,
82 | type: 'js',
83 | };
84 |
85 | stream.on('error', done);
86 | stream.on('data', (newFile) => {
87 | assert.strictEqual(newFile.contents.toString(), '');
88 | assert.strictEqual(newFile.jsbeautify.beautified, false);
89 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
90 | assert.strictEqual(newFile.jsbeautify.type, 'js');
91 | assert.strictEqual(process.stdout.write.getCall(1).args[0], `Already beautified ${colors.cyan('file.js')} [js]\n`);
92 | done();
93 | });
94 | stream.write(vinylFile);
95 | });
96 |
97 | it('should not report which files are already beautified without specify log verbosity', (done) => {
98 | const stream = beautify.reporter();
99 | const vinylFile = helper.createFile('file.js', '');
100 | vinylFile.jsbeautify = {
101 | beautified: false,
102 | canBeautify: false,
103 | type: 'js',
104 | };
105 |
106 | stream.on('error', done);
107 | stream.on('data', (newFile) => {
108 | assert.strictEqual(newFile.contents.toString(), '');
109 | assert.strictEqual(newFile.jsbeautify.beautified, false);
110 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
111 | assert.strictEqual(newFile.jsbeautify.type, 'js');
112 | sinon.assert.notCalled(process.stdout.write);
113 | done();
114 | });
115 | stream.write(vinylFile);
116 | });
117 |
118 | it('should report which files can be beautified with log verbosity set to ALL', (done) => {
119 | const stream = beautify.reporter({
120 | verbosity: beautify.report.ALL,
121 | });
122 | const vinylFile = helper.createFile('file.js', '');
123 | vinylFile.jsbeautify = {
124 | beautified: false,
125 | canBeautify: true,
126 | type: 'js',
127 | };
128 |
129 | stream.on('error', done);
130 | stream.on('data', (newFile) => {
131 | assert.strictEqual(newFile.contents.toString(), '');
132 | assert.strictEqual(newFile.jsbeautify.beautified, false);
133 | assert.strictEqual(newFile.jsbeautify.canBeautify, true);
134 | assert.strictEqual(newFile.jsbeautify.type, 'js');
135 | assert.strictEqual(process.stdout.write.getCall(1).args[0], `Can beautify ${colors.cyan('file.js')} [js]\n`);
136 | done();
137 | });
138 | stream.write(vinylFile);
139 | });
140 |
141 | it('should report which files can be beautified without specify log verbosity', (done) => {
142 | const stream = beautify.reporter();
143 | const vinylFile = helper.createFile('file.js', '');
144 | vinylFile.jsbeautify = {
145 | beautified: false,
146 | canBeautify: true,
147 | type: 'js',
148 | };
149 |
150 | stream.on('error', done);
151 | stream.on('data', (newFile) => {
152 | assert.strictEqual(newFile.contents.toString(), '');
153 | assert.strictEqual(newFile.jsbeautify.beautified, false);
154 | assert.strictEqual(newFile.jsbeautify.canBeautify, true);
155 | assert.strictEqual(newFile.jsbeautify.type, 'js');
156 | assert.strictEqual(process.stdout.write.getCall(1).args[0], `Can beautify ${colors.cyan('file.js')} [js]\n`);
157 | done();
158 | });
159 | stream.write(vinylFile);
160 | });
161 |
162 | // TODO
163 | it('should emit an error if a file can be beautified', (done) => {
164 | const stream = beautify.reporter();
165 | const vinylFile = helper.createFile('file.js', '');
166 | vinylFile.jsbeautify = {
167 | beautified: false,
168 | canBeautify: true,
169 | type: 'js',
170 | };
171 |
172 | stream.on('data', (newFile) => {
173 | assert.strictEqual(newFile.contents.toString(), '');
174 | assert.strictEqual(newFile.jsbeautify.beautified, false);
175 | assert.strictEqual(newFile.jsbeautify.canBeautify, true);
176 | assert.strictEqual(newFile.jsbeautify.type, 'js');
177 | done();
178 | });
179 |
180 | stream.write(vinylFile);
181 | });
182 |
183 | it('should report which files can not be beautified with log verbosity set to ALL', (done) => {
184 | const stream = beautify.reporter({
185 | verbosity: beautify.report.ALL,
186 | });
187 | const vinylFile = helper.createFile('file.js', '');
188 | vinylFile.jsbeautify = {
189 | beautified: false,
190 | canBeautify: false,
191 | type: null,
192 | };
193 |
194 | stream.on('error', done);
195 | stream.on('data', (newFile) => {
196 | assert.strictEqual(newFile.contents.toString(), '');
197 | assert.strictEqual(newFile.jsbeautify.beautified, false);
198 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
199 | assert.strictEqual(newFile.jsbeautify.type, null);
200 | assert.strictEqual(process.stdout.write.getCall(1).args[0], `Can not beautify ${colors.cyan('file.js')}\n`);
201 | done();
202 | });
203 | stream.write(vinylFile);
204 | });
205 |
206 | it('should not report which files can not be beautified without specify log verbosity', (done) => {
207 | const stream = beautify.reporter();
208 | const vinylFile = helper.createFile('file.js', '');
209 | vinylFile.jsbeautify = {
210 | beautified: false,
211 | canBeautify: false,
212 | type: null,
213 | };
214 |
215 | stream.on('error', done);
216 | stream.on('data', (newFile) => {
217 | assert.strictEqual(newFile.contents.toString(), '');
218 | assert.strictEqual(newFile.jsbeautify.beautified, false);
219 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
220 | assert.strictEqual(newFile.jsbeautify.type, null);
221 | sinon.assert.notCalled(process.stdout.write);
222 | done();
223 | });
224 | stream.write(vinylFile);
225 | });
226 | });
227 |
--------------------------------------------------------------------------------
/test/beautify.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const del = require('del');
3 | const fs = require('fs');
4 | const path = require('path');
5 | const sinon = require('sinon');
6 | const beautify = require('..');
7 | const helper = require('./helper');
8 |
9 | describe('beautify()', () => {
10 | beforeEach(() => {
11 | sinon.spy(process.stdout, 'write');
12 | });
13 |
14 | afterEach(() => {
15 | sinon.restore();
16 | });
17 |
18 | it('should ignore null file', (done) => {
19 | const stream = beautify();
20 | const vinylFile = helper.createFile('nullFile', null);
21 |
22 | stream.on('error', done);
23 | stream.on('data', (newFile) => {
24 | assert.strictEqual(newFile.contents, null);
25 | assert.strictEqual(newFile.jsbeautify, undefined);
26 | sinon.assert.notCalled(process.stdout.write);
27 | done();
28 | });
29 | stream.write(vinylFile);
30 | });
31 |
32 | it('should emit error with stream', (done) => {
33 | const stream = beautify();
34 | const vinylFile = {
35 | isNull() { return false; },
36 | isStream() { return true; },
37 | };
38 |
39 | stream.on('error', (err) => {
40 | assert.strictEqual(err.message, 'Streaming not supported');
41 | done();
42 | });
43 | stream.write(vinylFile);
44 | });
45 |
46 | it('should print debug messages when \'debug\' options is true', (done) => {
47 | const filePath = path.join(__dirname, 'fileOptions.json');
48 |
49 | fs.writeFileSync(filePath, '{}');
50 |
51 | const stream = beautify({
52 | debug: true,
53 | config: filePath,
54 | });
55 | const vinylFile = helper.createFile('file.js', '');
56 | vinylFile.jsbeautify = {};
57 | vinylFile.jsbeautify.type = null;
58 | vinylFile.jsbeautify.beautified = false;
59 |
60 | stream.on('error', done);
61 | stream.on('data', (newFile) => {
62 | assert.strictEqual(newFile.contents.toString(), '');
63 | assert.strictEqual(newFile.jsbeautify.beautified, false);
64 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
65 | assert.strictEqual(newFile.jsbeautify.type, 'js');
66 | assert(process.stdout.write.getCall(1).args[0].startsWith('File options:'));
67 | assert(process.stdout.write.getCall(3).args[0].startsWith('Final options:'));
68 | done();
69 | del.sync(filePath);
70 | });
71 | stream.on('close', () => del.sync(filePath));
72 | stream.write(vinylFile);
73 | });
74 |
75 | describe('with default options', () => {
76 | helper.supportedFiles.forEach((file) => {
77 | it(`should beautify '${file.name}'`, (done) => {
78 | const stream = beautify();
79 | const vinylFile = helper.createFile(file.name, helper.defaultContents[file.type].actual);
80 |
81 | stream.on('error', done);
82 | stream.on('data', (newFile) => {
83 | assert.strictEqual(newFile.contents.toString(), helper.defaultContents[file.type].expected);
84 | assert.strictEqual(newFile.jsbeautify.beautified, true);
85 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
86 | assert.strictEqual(newFile.jsbeautify.type, file.type);
87 | sinon.assert.notCalled(process.stdout.write);
88 | done();
89 | });
90 | stream.write(vinylFile);
91 | });
92 | });
93 |
94 | helper.notSupportedFiles.forEach((file) => {
95 | it(`should ignore '${file.name}'`, (done) => {
96 | const stream = beautify();
97 | const vinylFile = helper.createFile(file.name, helper.defaultContents[file.type].actual);
98 |
99 | stream.on('error', done);
100 | stream.on('data', (newFile) => {
101 | assert.strictEqual(newFile.contents.toString(), helper.defaultContents[file.type].actual);
102 | assert.strictEqual(newFile.jsbeautify.beautified, false);
103 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
104 | assert.strictEqual(newFile.jsbeautify.type, null);
105 | sinon.assert.notCalled(process.stdout.write);
106 | done();
107 | });
108 | stream.write(vinylFile);
109 | });
110 | });
111 | });
112 |
113 | describe('modifying the \'file_type\' option', () => {
114 | helper.supportedFiles.concat(helper.notSupportedFiles).forEach((file) => {
115 | it(`should beautify '${file.name}'`, (done) => {
116 | const stream = beautify({
117 | css: {
118 | file_types: ['.css.erb'],
119 | },
120 | html: {
121 | file_types: ['.html.erb'],
122 | },
123 | js: {
124 | file_types: ['.js.erb'],
125 | },
126 | });
127 | const vinylFile = helper.createFile(file.name, helper.defaultContents[file.type].actual);
128 |
129 | stream.on('error', done);
130 | stream.on('data', (newFile) => {
131 | assert.strictEqual(newFile.contents.toString(), helper.defaultContents[file.type].expected);
132 | assert.strictEqual(newFile.jsbeautify.beautified, true);
133 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
134 | assert.strictEqual(newFile.jsbeautify.type, file.type);
135 | sinon.assert.notCalled(process.stdout.write);
136 | done();
137 | });
138 | stream.write(vinylFile);
139 | });
140 | });
141 | });
142 |
143 | describe('with custom plugin options', () => {
144 | helper.supportedFiles.forEach((file) => {
145 | it(`should beautify '${file.name}'`, (done) => {
146 | const stream = beautify(helper.customOptions);
147 | const vinylFile = helper.createFile(file.name, helper.customContents[file.type].actual);
148 |
149 | stream.on('error', done);
150 | stream.on('data', (newFile) => {
151 | assert.strictEqual(newFile.contents.toString(), helper.customContents[file.type].expected);
152 | assert.strictEqual(newFile.jsbeautify.beautified, true);
153 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
154 | assert.strictEqual(newFile.jsbeautify.type, file.type);
155 | sinon.assert.notCalled(process.stdout.write);
156 | done();
157 | });
158 | stream.write(vinylFile);
159 | });
160 | });
161 | });
162 |
163 | describe('specifying a JSON file with \'config\' option', () => {
164 | const filePath = path.join(__dirname, 'fileOptions.json');
165 |
166 | before(() => {
167 | fs.writeFileSync(filePath, JSON.stringify(helper.customOptions));
168 | });
169 |
170 | after(() => {
171 | del.sync(filePath);
172 | });
173 |
174 | helper.supportedFiles.forEach((file) => {
175 | it(`should beautify '${file.name}'`, (done) => {
176 | const stream = beautify({ config: filePath });
177 | const vinylFile = helper.createFile(file.name, helper.customContents[file.type].actual);
178 |
179 | stream.on('error', done);
180 | stream.on('data', (newFile) => {
181 | assert.strictEqual(newFile.contents.toString(), helper.customContents[file.type].expected);
182 | assert.strictEqual(newFile.jsbeautify.beautified, true);
183 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
184 | assert.strictEqual(newFile.jsbeautify.type, file.type);
185 | sinon.assert.notCalled(process.stdout.write);
186 | done();
187 | });
188 | stream.write(vinylFile);
189 | });
190 | });
191 | });
192 |
193 | describe('specifying a YAML file with \'config\' option', () => {
194 | const filePath = path.join(__dirname, 'fileOptions.yml');
195 |
196 | before(() => {
197 | fs.writeFileSync(filePath, 'indent_char: " "\nindent_size: 2\ncss:\n indent_size: 1\nhtml:\n indent_char: "\t"\n indent_size: 1');
198 | });
199 |
200 | after(() => {
201 | del.sync(filePath);
202 | });
203 |
204 | helper.supportedFiles.forEach((file) => {
205 | it(`should beautify '${file.name}'`, (done) => {
206 | const stream = beautify({ config: filePath });
207 | const vinylFile = helper.createFile(file.name, helper.customContents[file.type].actual);
208 |
209 | stream.on('error', done);
210 | stream.on('data', (newFile) => {
211 | assert.strictEqual(newFile.contents.toString(), helper.customContents[file.type].expected);
212 | assert.strictEqual(newFile.jsbeautify.beautified, true);
213 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
214 | assert.strictEqual(newFile.jsbeautify.type, file.type);
215 | sinon.assert.notCalled(process.stdout.write);
216 | done();
217 | });
218 | stream.write(vinylFile);
219 | });
220 | });
221 | });
222 |
223 | describe('with an autoloaded \'.jsbeautifyrc\' file', () => {
224 | const filePath = path.join(process.cwd(), '.jsbeautifyrc');
225 |
226 | before(() => {
227 | fs.writeFileSync(filePath, JSON.stringify(helper.customOptions));
228 | });
229 |
230 | after(() => {
231 | del.sync(filePath);
232 | });
233 |
234 | helper.supportedFiles.forEach((file) => {
235 | it(`should beautify '${file.name}'`, (done) => {
236 | const stream = beautify({});
237 | const vinylFile = helper.createFile(file.name, helper.customContents[file.type].actual);
238 |
239 | stream.on('error', done);
240 | stream.on('data', (newFile) => {
241 | assert.strictEqual(newFile.contents.toString(), helper.customContents[file.type].expected);
242 | assert.strictEqual(newFile.jsbeautify.beautified, true);
243 | assert.strictEqual(newFile.jsbeautify.canBeautify, false);
244 | assert.strictEqual(newFile.jsbeautify.type, file.type);
245 | sinon.assert.notCalled(process.stdout.write);
246 | done();
247 | });
248 | stream.write(vinylFile);
249 | });
250 | });
251 | });
252 | });
253 |
--------------------------------------------------------------------------------