Skip to content

Commit 640be81

Browse files
orblazerazz
orblazer
authored andcommitted
feat: add format method, update dependencies (#12)
* feat: update packages * fix: Fix import on CLI * refactor: use relative package for prettier and tslint * fix: fix mock fs * feat: add format function for prettier-vscode * fix: fix lint errors * Clean the pull request * fix: travis ci build
1 parent ded16d3 commit 640be81

14 files changed

+1720
-796
lines changed

.eslintrc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"extends": ["eslint:recommended"],
44
"plugins": ["prettier"],
55
"env": {
6-
"es6": true
6+
"es6": true,
7+
"node": true
78
},
89
"globals": {
910
"process": true,

__mocks__/fs.js

+21-21
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,51 @@
1-
import path from "path";
2-
3-
const actual = require.requireActual("fs");
1+
const path = require("path");
2+
const actualFs = require.requireActual("fs");
43

54
let writes = Object.create(null);
65

7-
export const readdirSync = jest.fn(actual.readdirSync);
8-
export const statSync = jest.fn(actual.statSync);
6+
const readdirSync = jest.fn(actualFs.readdirSync);
7+
const statSync = jest.fn(actualFs.statSync);
98

10-
export const existsSync = jest.fn(filePath => {
9+
const existsSync = jest.fn(filePath => {
1110
const relative = path.relative(process.cwd(), filePath);
1211
if (relative in writes) {
1312
return true;
1413
}
15-
return actual.existsSync(filePath);
16-
});
17-
18-
export const writeFileSync = jest.fn((filePath, content) => {
19-
const relative = path.relative(process.cwd(), filePath);
20-
writes[relative] = content;
14+
return actualFs.existsSync(filePath);
2115
});
2216

23-
export const readFileSync = jest.fn(filePath => {
17+
const readFileSync = jest.fn(filePath => {
2418
const relative = path.relative(process.cwd(), filePath);
2519
if (relative in writes) {
2620
return writes[relative];
2721
}
28-
return actual.readFileSync(filePath, "utf8");
22+
return actualFs.readFileSync(filePath, "utf8");
23+
});
24+
25+
const writeFileSync = jest.fn((filePath, content) => {
26+
const relative = path.relative(process.cwd(), filePath);
27+
writes[relative] = content;
2928
});
3029

31-
export const __clear = () => {
30+
function __clear() {
3231
writes = Object.create(null);
3332
readdirSync.mockClear();
3433
existsSync.mockClear();
3534
statSync.mockClear();
36-
writeFileSync.mockClear();
3735
readFileSync.mockClear();
38-
};
36+
writeFileSync.mockClear();
37+
}
3938

40-
export const __setContents = (filePath, contents) => {
39+
function __setContents(filePath, contents) {
4140
writes[filePath] = contents;
42-
};
41+
}
4342

44-
export default {
43+
module.exports = Object.assign({}, actualFs, {
4544
__clear,
4645
__setContents,
46+
readdirSync,
4747
existsSync,
4848
statSync,
4949
readFileSync,
5050
writeFileSync,
51-
};
51+
});

package.json

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
{
22
"name": "prettier-tslint",
3-
"description": "Formats your TypeScript using Prettier followed by tslint --fix",
3+
"description":
4+
"Formats your TypeScript using Prettier followed by tslint --fix",
45
"version": "0.0.0-development",
56
"author": "Lucas Azzola <@azz>",
67
"license": "MIT",
78
"main": "dist",
89
"bin": "./bin/prettier-tslint.js",
9-
"files": [
10-
"bin",
11-
"dist"
12-
],
10+
"files": ["bin", "dist"],
1311
"dependencies": {
14-
"chalk": "^2.2.0",
15-
"globby": "^6.1.0",
16-
"ignore": "^3.3.5",
17-
"tslint": "^5.7.0",
18-
"yargs": "^9.0.1"
12+
"chalk": "^2.4.0",
13+
"globby": "^8.0.1",
14+
"ignore": "^3.3.7",
15+
"require-relative": "^0.8.7",
16+
"tslint": "^5.9.1",
17+
"yargs": "^11.0.0"
1918
},
2019
"peerDependencies": {
2120
"prettier": "^1.7.4",
@@ -24,19 +23,20 @@
2423
"devDependencies": {
2524
"babel-cli": "^6.26.0",
2625
"babel-preset-env": "^1.6.1",
27-
"eslint": "^4.9.0",
28-
"eslint-config-prettier": "^2.6.0",
29-
"eslint-plugin-prettier": "^2.3.1",
26+
"eslint": "^4.19.1",
27+
"eslint-config-prettier": "^2.9.0",
28+
"eslint-plugin-prettier": "^2.6.0",
3029
"jest": "^21.2.1",
31-
"prettier": "1.7.4",
30+
"prettier": "1.12.1",
3231
"semantic-release": "^8.0.3",
33-
"typescript": "~2.5.3"
32+
"typescript": "~2.8.3"
3433
},
3534
"scripts": {
3635
"lint": "eslint .",
3736
"test": "jest",
3837
"build": "babel --copy-files --out-dir dist src",
39-
"semantic-release": "semantic-release pre && npm publish && semantic-release post"
38+
"semantic-release":
39+
"semantic-release pre && npm publish && semantic-release post"
4040
},
4141
"repository": {
4242
"type": "git",

src/apply-fixes.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function applyTSLintAllFixes(linterResults, source, tslint) {
2+
const fixes = [];
3+
linterResults.failures.forEach(failure => {
4+
if (failure.hasFix()) {
5+
fixes.push(failure.getFix());
6+
}
7+
});
8+
9+
return tslint.Replacement.applyFixes(source, fixes);
10+
}

src/cli.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import yargs, { showHelp } from "yargs";
66
import fix from "./fix";
77
import check from "./check";
88
import expandGlobs from "./expand-globs";
9-
import createIgnorer from "./create-ignoger";
9+
import createIgnorer from "./create-ignorer";
1010

1111
const cli = argv => {
12-
const { _: [command, ...patterns] } = yargs
12+
const {
13+
_: [command, ...patterns],
14+
} = yargs
1315
// Fix
1416
.command("fix", "Fix one or more files")
1517
.example("prettier-tslint fix file1.ts file2.ts", "Fix provided files")

src/format.js

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { readFileSync } from "fs";
2+
import { applyTSLintAllFixes } from "./apply-fixes";
3+
import { requireModule, getModulePath, getPrettierConfig } from "./utils";
4+
5+
/**
6+
* Formats the text with prettier and then eslint based on the given options
7+
* @param {String} options.filePath - the path of the file being formatted
8+
* can be used in leu of `eslintConfig` (eslint will be used to find the
9+
* relevant config for the file). Will also be used to load the `text` if
10+
* `text` is not provided.
11+
* @param {String} options.text - the text (TypeScript code) to format
12+
* @param {String} options.tslintPath - the path to the tslint module to use.
13+
* Will default to require.resolve('tslint')
14+
* @param {String} options.prettierPath - the path to the prettier module.
15+
* Will default to require.resovlve('prettier')
16+
* @param {Object} options.tslintConfig - the config to use for formatting
17+
* with TSLint.
18+
* @param {Object} options.prettierOptions - the options to pass for
19+
* formatting with `prettier`. If not provided, prettier-eslint will attempt
20+
* to create the options based on the eslintConfig
21+
* @param {Object} options.fallbackPrettierOptions - the options to pass for
22+
* formatting with `prettier` if the given option is not inferrable from the
23+
* eslintConfig.
24+
* @param {Boolean} options.prettierLast - Run Prettier Last
25+
* @return {String} - the formatted string
26+
*/
27+
export default function format(options) {
28+
const {
29+
filePath,
30+
text = readFileSync(filePath, "utf8"),
31+
tslintPath = getModulePath(filePath, "tslint"),
32+
prettierPath = getModulePath(filePath, "prettier"),
33+
prettierLast,
34+
fallbackPrettierOptions,
35+
} = options;
36+
37+
const tslintConfig = Object.assign(
38+
{},
39+
options.tslintConfig,
40+
getTSLintConfig(filePath, tslintPath)
41+
);
42+
43+
const prettierOptions = Object.assign(
44+
{},
45+
filePath && { filepath: filePath },
46+
getPrettierConfig(filePath),
47+
options.prettierOptions
48+
);
49+
50+
const prettify = createPrettify(
51+
prettierOptions || fallbackPrettierOptions || {},
52+
prettierPath
53+
);
54+
const tslintFix = createTSLintFix(tslintConfig, tslintPath);
55+
56+
if (prettierLast) {
57+
return prettify(tslintFix(text, filePath));
58+
}
59+
return tslintFix(prettify(text), filePath);
60+
}
61+
62+
function createPrettify(formatOptions, prettierPath) {
63+
return function prettify(text) {
64+
const prettier = requireModule(prettierPath);
65+
try {
66+
const output = prettier.format(text, formatOptions);
67+
return output;
68+
} catch (error) {
69+
throw error;
70+
}
71+
};
72+
}
73+
74+
function createTSLintFix(tslintConfig, tslintPath) {
75+
return function tslintFix(text, filePath) {
76+
const tslint = requireModule(tslintPath);
77+
try {
78+
const linter = new tslint.Linter({
79+
fix: false,
80+
formatter: "json",
81+
});
82+
83+
linter.lint(filePath, text, tslintConfig);
84+
return applyTSLintAllFixes(linter.getResult(), text, tslint);
85+
} catch (error) {
86+
throw error;
87+
}
88+
};
89+
}
90+
91+
function getTSLintConfig(filePath, tslintPath) {
92+
const tslint = requireModule(tslintPath);
93+
try {
94+
return tslint.Configuration.findConfiguration(null, filePath).results;
95+
} catch (error) {
96+
return { rules: {} };
97+
}
98+
}

src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { default as cli } from "./cli";
2+
export { default as format } from "./format";
23
export { default as fix } from "./fix";
34
export { default as check } from "./check";

src/run-prettier.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
import { readFileSync, writeFileSync } from "fs";
2-
import { format, check, resolveConfig } from "prettier";
2+
import { requireModule, getModulePath, getPrettierConfig } from "./utils";
33

44
/**
55
* @returns true iff output === input
66
*/
77
const runPrettier = (filepath, fix) => {
8-
const config = resolveConfig.sync(filepath);
8+
const prettier = requireModule(getModulePath(filepath, "prettier"));
9+
const config = getPrettierConfig(filepath, prettier);
910
const code = readFileSync(filepath, "utf8");
1011
const options = Object.assign({ filepath }, config);
1112

1213
if (fix) {
13-
const output = format(code, options);
14+
const output = prettier.format(code, options);
1415
if (output !== code) {
1516
writeFileSync(filepath, output);
1617
return false;
1718
}
1819
return true;
1920
} else {
20-
return check(code, options);
21+
return prettier.check(code, options);
2122
}
2223
};
2324

src/run-tslint.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { readFileSync } from "fs";
2-
import { Configuration, Linter } from "tslint";
2+
import { requireModule, getModulePath } from "./utils";
33
import createProgram from "./create-program";
44

55
/**
66
* @returns true iff output === input
77
*/
88
const runTsLint = (filepath, fix) => {
9+
const tslint = requireModule(getModulePath(filepath, "tslint"));
910
const code = readFileSync(filepath, "utf8");
10-
const config = Configuration.findConfiguration(null, filepath).results;
11+
const config = tslint.Configuration.findConfiguration(null, filepath).results;
1112

1213
const program = createProgram(filepath);
1314

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

1718
linter.lint(filepath, code, config);
1819
const result = linter.getResult();

src/utils.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import requireRelative from "require-relative";
2+
3+
export function requireModule(modulePath) {
4+
try {
5+
return require(modulePath);
6+
} catch (error) {
7+
throw error;
8+
}
9+
}
10+
11+
export function getModulePath(filePath, moduleName) {
12+
try {
13+
return requireRelative.resolve(moduleName, filePath);
14+
} catch (error) {
15+
return require.resolve(moduleName);
16+
}
17+
}
18+
19+
export function getPrettierConfig(
20+
filePath,
21+
prettier = requireModule(getModulePath(filePath, "prettier"))
22+
) {
23+
return (
24+
(prettier.resolveConfig &&
25+
prettier.resolveConfig.sync &&
26+
prettier.resolveConfig.sync(filePath)) ||
27+
{}
28+
);
29+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`format() bad format, bad lint passes format 1`] = `
4+
"throw new Error(\\"no-string-throw\\");
5+
"
6+
`;
7+
8+
exports[`format() bad format, good lint passes format 1`] = `
9+
"throw new Error(\\"no-string-throw\\");
10+
"
11+
`;
12+
13+
exports[`format() good format, bad lint passes format 1`] = `
14+
"throw new Error(\\"no-string-throw\\");
15+
"
16+
`;
17+
18+
exports[`format() good format, good lint passes format 1`] = `
19+
"throw new Error(\\"no-string-throw\\");
20+
"
21+
`;

0 commit comments

Comments
 (0)