Skip to content
This repository has been archived by the owner on Oct 4, 2020. It is now read-only.

New features for CLI #55

Merged
merged 1 commit into from
Mar 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ insert_final_newline = true
[{*.json,*.yml}]
indent_style = space
indent_size = 2

[README.md]
indent_style = ignore
indent_size = ignore
40 changes: 20 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This version of ECLint runs on [EditorConfig Core](https://www.npmjs.com/package

## Installation

```
```bash
$ npm install [-g] eclint
```

Expand All @@ -45,7 +45,7 @@ The command-line interface (CLI) for this project uses [gitlike-cli](https://www

Running just `eclint` will provide the following help information:

```
```bash
$ eclint

CommandError: Missing required sub-command.
Expand All @@ -67,14 +67,14 @@ $ eclint

## Check

The `eclint check` sub-command allows you to validate that files adhere to their respective EditorConfig settings. Running just `eclint check` will provide you the following help information:
The `eclint check` sub-command allows you to validate that files adhere to their respective EditorConfig settings. Running `eclint check --help` will provide you the following help information:

```
```bash
$ eclint check

CommandError: Missing required arguments.
Validate that file(s) adhere to .editorconfig settings

Usage: check [options] <files>...
Usage: check [options] [<files>...]

Options:

Expand All @@ -93,7 +93,7 @@ Running this sub-command without any `[options]` will use each file's EditorConf

Each CLI option has both short and long flag variations. As such, you can use `--indent_size 2` or `-i 2`, whichever you prefer. Short flags may be combined into a single argument. For example, `-swe 2 lf` is the same as `-s 2 -w -e lf`.

The `<files>...` args allows you to pass-in one or more file paths or [globs](https://github.com/isaacs/node-glob). You may, however, need to surround your glob expressions in quotes for it to work properly. Unfortunately, in bash, you can't add a negative glob with "!foo.js". Instead, you can put square brackets around the `!` and eclint will take care of it. For example, "[!]foo.js".
The `[<files>...]` args allows you to pass-in one or more file paths or [globs](https://github.com/isaacs/node-glob). You may, however, need to surround your glob expressions in quotes for it to work properly. Unfortunately, in bash, you can't add a negative glob with "!foo.js". Instead, you can put square brackets around the `!` and eclint will take care of it. For example, "[!]foo.js".

The result of running `eclint check *` in this project's root, if there were issues, would look something like the following:

Expand Down Expand Up @@ -127,14 +127,14 @@ Now should be a great time to segue into the [fix sub-command](#fix).
</tr>
</table>

The `eclint fix` sub-command allows you to fix files that don't adhere to their respective EditorConfig settings. Running just `eclint fix` will provide you the following help information:
The `eclint fix` sub-command allows you to fix files that don't adhere to their respective EditorConfig settings. Running `eclint fix --help` will provide you the following help information:

```
```bash
$ eclint fix

CommandError: Missing required arguments.
Fix formatting errors that disobey .editorconfig settings

Usage: fix [options] <files>...
Usage: fix [options] [<files>...]

Options:

Expand All @@ -157,14 +157,14 @@ One key difference you'll notice is an additional `-d, --dest <folder>` option.

## Infer

The `eclint infer` sub-command allows you to infer what the EditorConfig settings **_should_** be for all files you specify. Running just `eclint infer` will provide you the following help information:
The `eclint infer` sub-command allows you to infer what the EditorConfig settings **_should_** be for all files you specify. Running `eclint infer --help` will provide you the following help information:

```
```bash
$ eclint infer

CommandError: Missing required arguments.
Infer .editorconfig settings from one or more files

Usage: infer [options] <files>...
Usage: infer [options] [<files>...]

Options:

Expand All @@ -178,7 +178,7 @@ This sub-command generates a report that reveals whatever trends you have growin

By default, the CLI will print out the report in JSON format.

```
```bash
$ eclint infer * "lib/**/*.js"
```

Expand All @@ -196,7 +196,7 @@ Outputs:

If this isn't enough information for you and you want the full report, complete with scores, you can add the `-s, --score` flag. Each setting will have a numeric value assigned to it that indicates the number of times that setting was inferred across the files:

```
```bash
$ eclint infer --score * "lib/**/*.js"
```

Expand Down Expand Up @@ -230,19 +230,19 @@ Outputs:

You can pipe these files to any destination file you wish, like so:

```
```bash
$ eclint infer * "lib/**/*.js" > editorconfig.json
```

You can also use the `-i, --ini` flag to generate the report as an INI file format, which is exactly the format in which the `.editorconfig` file should be written. This means you can create your `.editorconfig` file automatically! Here's how you might do it:

```
```bash
$ eclint infer --ini * "lib/**/*.js" > .editorconfig
```

If this is your root `.editorconfig` file, you'll definitely want to pair the `-i, --ini` flag with the `-r, --root` flag to add `root = true` to your `.editorconfig` file. We'll combine the 2 short flags into one:

```
```bash
$ eclint infer -ir * "lib/**/*.js" > .editorconfig
```

Expand Down
53 changes: 53 additions & 0 deletions lib/cli.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import common = require('./test-common');
const execFile = require('child_process').execFile;
const cliPath = require.resolve('../bin/eclint');
const expect = common.expect;

// ReSharper disable WrongExpressionStatement
describe('eclint cli', function() {
function eclint(args: string[], callback?: any) {
args.unshift(cliPath);
return execFile(process.execPath, args, callback);
}
this.timeout(8000);
it('Missing sub-command', (done) => {
eclint([], (error: Error) => {
expect(error.message).to.be.match(/\bCommandError\b/);
expect(error.message).to.be.match(/\bMissing required sub-command\b/);
done();
});
});
describe('check', () => {
it('README.md', (done) => {
eclint(['check', 'README.md'], done);
});
it('images/*', (done) => {
eclint(['check', 'images/*'], done);
});
it('node_modules/.bin/_mocha', (done) => {
eclint(['check', 'node_modules/.bin/_mocha'], (error: Error) => {
expect(error.message).to.be.match(/\binvalid indentation\b/);
done();
});
});
});
describe('infer', function() {
it('lib/**/*', (done) => {
eclint(['infer', '--ini', 'lib/**/*'], (error, stdout, stderr) => {
if (error) {
done(error);
} else {
expect(stdout).to.be.match(/\bindent_style = tab\b/);
expect(stderr).not.to.be.ok;
done();
}
});
});
it('README.md', (done) => {
eclint(['infer', 'README.md'], done);
});
it('node_modules/.bin/_mocha', (done) => {
eclint(['infer', 'node_modules/.bin/_mocha'], done);
});
});
});
49 changes: 32 additions & 17 deletions lib/cli.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import _ = require('lodash');
var tap = require('gulp-tap');
const tap = require('gulp-tap');
import File = require('vinyl');
import vfs = require('vinyl-fs');
import gutil = require('gulp-util');

import eclint = require('./eclint');

var cli = require('gitlike-cli');
var pkg = require('../package');
var reporter = require('gulp-reporter');
const cli = require('gitlike-cli');
const pkg = require('../package');
const reporter = require('gulp-reporter');
const filter = require('gulp-filter');
const fileType = require('file-type');
const binaryexts = require('binaryextensions');

cli.on('error', err => {
console.log('');
console.log(gutil.colors.red(' ' + err.name + ':', err.message));
console.error('\n ' + gutil.colors.red(err.toString()));
err.command.outputUsage();
err.command.outputCommands();
err.command.outputOptions();
console.log();
process.exit(1);
});

Expand All @@ -34,26 +35,38 @@ function addSettings(cmd): void {
cmd.option('-m, --max_line_length <n>', 'Set to a whole number');
}

function excludeBinaryFile(file: File) {
const type = file && file.isBuffer() && fileType(file.contents);
return !(type && type.ext && binaryexts.indexOf(type.ext) >= 1);
}

interface CheckOptions extends eclint.Settings {
reporter?: (file: File, message: string) => void;
}

function handleNegativeGlobs(files: string[]): any {
return files.map(glob => {
return glob.replace(/^\[!\]/, '!');
});
function handleNegativeGlobs(files?: string[]): string[] {
if (!files) {
return ['**/*', '!**/.git', '!**/.svn', '!**/.hg', '!**/.DS_Store', '!**/node_modules', '!**/bower_components'];
}
return files.filter(file => (
typeof file === 'string'
)).map(glob => (
glob.replace(/^\[!\]/, '!')
));
}

var check = cli.command('check <files>...');
const check = cli.command('check [<files>...]');
check.description('Validate that file(s) adhere to .editorconfig settings');
addSettings(check);
check.action((args: any, options: CheckOptions) => {
var stream = vfs.src(handleNegativeGlobs(args.files.filter(file => (typeof file === 'string'))), {
const stream = vfs.src(handleNegativeGlobs(args.files), {
stripBOM: false
})
.pipe(filter(excludeBinaryFile))
.pipe(eclint.check({
settings: _.pick(options, eclint.ruleNames),
})).pipe(reporter({
console: console.error,
filter: null,
}))
.on('error', (error) => {
Expand All @@ -72,14 +85,15 @@ interface FixOptions extends eclint.Settings {
dest?: string;
}

var fix = cli.command('fix <files>...');
const fix = cli.command('fix [<files>...]');
fix.description('Fix formatting errors that disobey .editorconfig settings');
addSettings(fix);
fix.option('-d, --dest <folder>', 'Destination folder to pipe source files');
fix.action((args: any, options: FixOptions) => {
var stream = vfs.src(handleNegativeGlobs(args.files.filter(file => (typeof file === 'string'))), {
const stream = vfs.src(handleNegativeGlobs(args.files), {
stripBOM: false
})
.pipe(filter(excludeBinaryFile))
.pipe(eclint.fix({ settings: _.pick(options, eclint.ruleNames) }));
if (options.dest) {
return stream.pipe(vfs.dest(options.dest));
Expand All @@ -89,15 +103,16 @@ fix.action((args: any, options: FixOptions) => {
}));
});

var infer = cli.command('infer <files>...');
const infer = cli.command('infer [<files>...]');
infer.description('Infer .editorconfig settings from one or more files');
infer.option('-s, --score', 'Shows the tallied score for each setting');
infer.option('-i, --ini', 'Exports file as ini file type');
infer.option('-r, --root', 'Adds root = true to your ini file, if any');
infer.action((args: any, options: eclint.InferOptions) => {
return vfs.src(handleNegativeGlobs(args.files.filter(file => (typeof file === 'string'))), {
return vfs.src(handleNegativeGlobs(args.files), {
stripBOM: false
})
.pipe(filter(excludeBinaryFile))
.pipe(eclint.infer(options))
.pipe(tap((file: File) => {
console.log(file.contents + '');
Expand Down
19 changes: 19 additions & 0 deletions lib/eclint.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ var expect = common.expect;

// ReSharper disable WrongExpressionStatement
describe('eclint gulp plugin', () => {
before(() => {
eclint.configure({
newlines: ['\n', '\r\n']
});
});
describe('fix file', () => {

it('fix by default options', (done) => {
Expand Down Expand Up @@ -113,6 +118,20 @@ describe('eclint gulp plugin', () => {
}));
});

it('options.reporter', (done) => {
var stream = eclint.check({
reporter: (_file: eclint.EditorConfigLintFile, error: Error) => {
expect(error.message).to.have.equal('invalid charset: utf-8-bom, expected: utf-8');
done();
}
});

stream.write(new File({
path: path.join(__dirname, "testcase.js"),
contents: new Buffer([0xef, 0xbb, 0xbf, 0x74, 0x65, 0x73, 0x74, 0x63, 0x61, 0x73, 0x65, 0x0a])
}));
});

});

describe('charset rule', () => {
Expand Down
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
"codecov": "codecov -f coverage/lcov.info",
"compile": "tsc",
"compile:watch": "tsc --watch",
"eclint": "node bin/eclint.js check * lib/**/*",
"lint": "npm run tslint",
"mocha": "mocha dist/**/*.spec.js",
"mocha": "mocha \"dist/**/*.spec.js\"",
"prepublish": "npm test",
"pretest": "npm run lint && npm run clean && npm run compile",
"pretest": "npm run lint && npm run clean && npm run compile && npm run eclint",
"test": "nyc npm run mocha -- --reporter lcov --reporter spec",
"test:watch": "npm run mocha -- --watch --reporter min",
"tslint": "tslint --project tsconfig.json"
Expand Down Expand Up @@ -56,9 +57,12 @@
"author": "EditorConfig Team",
"license": "MIT",
"dependencies": {
"binaryextensions": "^2.0.0",
"editorconfig": "^0.13.2",
"file-type": "^4.1.0",
"gitlike-cli": "^0.1.0",
"gulp-reporter": "^1.5.1",
"gulp-filter": "^5.0.0",
"gulp-reporter": "^1.5.2",
"gulp-tap": "^0.1.3",
"gulp-util": "^3.0.4",
"linez": "^4.1.4",
Expand Down