Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support fix and check commands #3

Merged
merged 1 commit into from Oct 21, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .babelrc
@@ -0,0 +1,3 @@
{
"presets": [["env", { "targets": { "node": "4.5" } }]]
}
3 changes: 2 additions & 1 deletion .eslintrc.json
Expand Up @@ -6,7 +6,8 @@
"es6": true
},
"globals": {
"process": true
"process": true,
"console": true
},
"rules": {
"curly": ["error"],
Expand Down
3 changes: 1 addition & 2 deletions .gitignore
@@ -1,4 +1,3 @@
node_modules
.esm-cache
.vscode
dist
*.log
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -15,6 +15,7 @@ install:
- yarn
script:
- yarn lint
- yarn build
- yarn test
after_success:
- npm run semantic-release
Expand Down
24 changes: 17 additions & 7 deletions README.md
Expand Up @@ -25,7 +25,7 @@ Or with `yarn`:
yarn add --dev prettier-tslint
```

## Confituration
## Configuration

`prettier-tslint` find and will respect:

Expand All @@ -37,17 +37,27 @@ yarn add --dev prettier-tslint

## CLI

```bash
pretttier-tslint file.ts
```
Commands:
fix Fix one or more files
check List files that aren't formatted

Options:
--version Show version number [boolean]
--help Show help [boolean]

Examples:
prettier-tslint fix file1.ts file2.ts Fix provided files
prettier-tslint fix '**/*.ts' Fix all TypeScript files
prettier-tslint check '**/*.ts' List all unformatted TypeScript files
```

## API


```js
import format from "prettier-eslint";
import { fix } from "prettier-tslint";

format("file.ts");
fix("file.ts");
```

Currently the `format` function will write to disk and not return anything. This behavior **will change** in a minor release before `1.0.0` is released.
Currently the `fix` function will write to disk and not return anything. This behavior **will change** in a minor release before `1.0.0` is released.
5 changes: 5 additions & 0 deletions __mocks__/.eslintrc.json
@@ -0,0 +1,5 @@
{
"env": {
"jest": true
}
}
37 changes: 37 additions & 0 deletions __mocks__/fs.js
@@ -0,0 +1,37 @@
import path from "path";

const actual = require.requireActual("fs");

let writes = {};

export const statSync = jest.fn(actual.statSync);
export const existsSync = jest.fn(actual.existsSync);

export const writeFileSync = jest.fn((filePath, content) => {
const relative = path.relative(process.cwd(), filePath);
writes[relative] = content;
});

export const readFileSync = jest.fn(filePath => {
const relative = path.relative(process.cwd(), filePath);
if (writes[relative]) {
return writes[relative];
}
return actual.readFileSync(filePath, "utf8");
});

export const __clear = () => {
writes = {};
existsSync.mockClear();
statSync.mockClear();
writeFileSync.mockClear();
readFileSync.mockClear();
};

export default {
__clear,
existsSync,
statSync,
readFileSync,
writeFileSync,
};
4 changes: 0 additions & 4 deletions index.js

This file was deleted.

16 changes: 10 additions & 6 deletions package.json
Expand Up @@ -4,34 +4,38 @@
"version": "0.0.0-development",
"author": "Lucas Azzola <@azz>",
"license": "MIT",
"main": "dist",
"bin": "./bin/prettier-tslint.js",
"files": [
"bin",
"src",
"index.js"
"dist"
],
"dependencies": {
"@std/esm": "^0.11.3",
"chalk": "^2.2.0",
"globby": "^6.1.0",
"ignore": "^3.3.5",
"minimist": "^1.2.0",
"tslint": "^5.7.0"
"tslint": "^5.7.0",
"yargs": "^9.0.1"
},
"peerDependencies": {
"prettier": "^1.7.4",
"typescript": "^2.5.3"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.6.1",
"eslint": "^4.9.0",
"eslint-config-prettier": "^2.6.0",
"eslint-plugin-prettier": "^2.3.1",
"jest": "^21.2.1",
"prettier": "1.7.4",
"semantic-release": "^8.0.3",
"typescript": "~2.5.3"
},
"scripts": {
"lint": "eslint .",
"test": "echo soon...",
"test": "jest",
"build": "babel --copy-files --out-dir dist src",
"semantic-release": "semantic-release pre && npm publish && semantic-release post"
},
"repository": {
Expand Down
8 changes: 8 additions & 0 deletions src/check.js
@@ -0,0 +1,8 @@
import runTsLint from "./run-tslint";
import runPrettier from "./run-prettier";

const check = filePath => {
return runPrettier(filePath, false) && runTsLint(filePath, false);
};

export default check;
56 changes: 56 additions & 0 deletions src/cli.js
@@ -0,0 +1,56 @@
/* eslint no-console: 0 */

import chalk from "chalk";
import yargs from "yargs";

import fix from "./fix";
import check from "./check";
import expandGlob from "./expand-glob";
import filterIgnored from "./filter-ignored";

const cli = argv => {
const yargsInstance = yargs
// Fix
.command("fix", "Fix one or more files")
.example("prettier-tslint fix file1.ts file2.ts", "Fix provided files")
.example("prettier-tslint fix '**/*.ts'", "Fix all .ts files")
// Check
.command("check", "List files that aren't formatted")
.example("prettier-tslint check '**/*.ts'", "List unformatted .ts files")
// Meta
.demandCommand(1, "Command not provided.")
.help();

const args = yargsInstance.parse(argv);
const command = args._[0];
const patterns = args._.slice(1);

switch (command) {
case "fix":
return patterns.forEach(fixFiles);
case "check":
return patterns.forEach(checkFiles);
default:
yargs.showHelp();
console.error(`Unknown command: ${command}`);
}
};

const fixFiles = filePattern => {
const files = filterIgnored(expandGlob(filePattern));
files.forEach(file => {
const changed = !fix(file);
console.log(changed ? file : chalk.gray(file));
});
};

const checkFiles = filePattern => {
const files = filterIgnored(expandGlob(filePattern));
const invalid = files.filter(file => !check(file));
if (invalid.length) {
process.exitCode = 1;
}
invalid.forEach(file => console.error(chalk.red.bold(file)));
};

export default cli;
9 changes: 6 additions & 3 deletions src/expand-glob.js
@@ -1,9 +1,12 @@
import globby from "globby";

const expandGlob = glob => {
return globby.sync(glob, {
dot: true,
});
return globby.sync(
[glob].concat(["!**/node_modules/**", "!./node_modules/**"]),
{
dot: true,
}
);
};

export default expandGlob;
10 changes: 10 additions & 0 deletions src/fix.js
@@ -0,0 +1,10 @@
import runTsLint from "./run-tslint";
import runPrettier from "./run-prettier";

const fix = filePath => {
const prettierCheck = runPrettier(filePath, true);
const tslintCheck = runTsLint(filePath, true);
return prettierCheck && tslintCheck;
};

export default fix;
27 changes: 3 additions & 24 deletions src/index.js
@@ -1,26 +1,5 @@
import fs from "fs";
import minimist from "minimist";

import expandGlob from "./expand-glob";
import filterIgnored from "./filter-ignored";
import runTsLint from "./run-tslint";
import runPrettier from "./run-prettier";

const format = filePath => {
runPrettier(filePath);
runTsLint(filePath);
};

const formatFiles = filePattern => {
const files = filterIgnored(expandGlob(filePattern));
files.forEach(format);
};

const cliOpts = {};

export const cli = argv => {
const args = minimist(argv, cliOpts);
args._.forEach(formatFiles);
};

export default format;
export { default as cli } from "./cli";
export { default as fix } from "./fix";
export { default as check } from "./check";
19 changes: 16 additions & 3 deletions src/run-prettier.js
@@ -1,11 +1,24 @@
import fs from "fs";
import prettier from "prettier";

const runPrettier = filepath => {
/**
* @returns true iff output === input
*/
const runPrettier = (filepath, fix) => {
const config = prettier.resolveConfig.sync(filepath);
const code = fs.readFileSync(filepath, "utf8");
const output = prettier.format(code, Object.assign({ filepath }, config));
fs.writeFileSync(filepath, output);
const options = Object.assign({ filepath }, config);

if (fix) {
const output = prettier.format(code, options);
if (output !== code) {
fs.writeFileSync(filepath, output);
return false;
}
return true;
} else {
return prettier.check(code, options);
}
};

export default runPrettier;
17 changes: 13 additions & 4 deletions src/run-tslint.js
@@ -1,19 +1,28 @@
import fs from "fs";
import tslint from "tslint";
import * as tslint from "tslint";
import createProgram from "./create-program";

const runTsLint = filepath => {
/**
* @returns true iff output === input
*/
const runTsLint = (filepath, fix) => {
const code = fs.readFileSync(filepath, "utf8");
const config = tslint.Configuration.findConfiguration(null, filepath).results;

const program = createProgram(filepath);

// TODO(azz): This actually writes over the file, we don't really want that...
const linter = new tslint.Linter({ fix: true }, program);
const linter = new tslint.Linter({ fix }, program);

linter.lint(filepath, code, config);
const result = linter.getResult();
return result;
if (fix) {
// There were no fixes applied
return result.fixes.length === 0;
} else {
// There were no auto-fixable problems
return !result.failures.find(failure => failure.fix);
}
};

export default runTsLint;
5 changes: 5 additions & 0 deletions test/.eslintrc.json
@@ -0,0 +1,5 @@
{
"env": {
"jest": true
}
}
25 changes: 25 additions & 0 deletions test/__snapshots__/fix.test.js.snap
@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`fix() bad format, bad lint writes fix to disk 1`] = `
Array [
"test/fixture/bad-format-bad-lint.ts",
"throw new Error(\\"no-string-throw\\");
",
]
`;

exports[`fix() bad format, good lint writes fix to disk 1`] = `
Array [
"test/fixture/bad-format-good-lint.ts",
"throw new Error(\\"no-string-throw\\");
",
]
`;

exports[`fix() good format, bad lint writes fix to disk 1`] = `
Array [
"test/fixture/good-format-bad-lint.ts",
"throw new Error(\\"no-string-throw\\");
",
]
`;
16 changes: 16 additions & 0 deletions test/check.test.js
@@ -0,0 +1,16 @@
import check from "../src/check";

describe("check()", () => {
test("good format, bad lint fails check", () => {
expect(check("test/fixture/good-format-bad-lint.ts")).toEqual(false);
});
test("bad format, good lint fails check", () => {
expect(check("test/fixture/bad-format-good-lint.ts")).toEqual(false);
});
test("bad format, bad lint fails check", () => {
expect(check("test/fixture/bad-format-bad-lint.ts")).toEqual(false);
});
test("good format, good lint passes check", () => {
expect(check("test/fixture/good-format-good-lint.ts")).toEqual(true);
});
});