1
+ import { extname } from "path" ;
1
2
import { readFileSync } from "fs" ;
2
- import { applyTSLintAllFixes } from "./apply-fixes" ;
3
3
import { requireModule , getModulePath , getPrettierConfig } from "./utils" ;
4
4
5
5
/**
@@ -25,74 +25,87 @@ import { requireModule, getModulePath, getPrettierConfig } from "./utils";
25
25
* @return {String } - the formatted string
26
26
*/
27
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 ;
28
+ const { filePath } = options ;
36
29
37
- const tslintConfig = Object . assign (
38
- { } ,
30
+ const tslintFix = createTSLintFix (
39
31
options . tslintConfig ,
40
- getTSLintConfig ( filePath , tslintPath )
41
- ) ;
42
-
43
- const prettierOptions = Object . assign (
44
- { } ,
45
- filePath && { filepath : filePath } ,
46
- getPrettierConfig ( filePath ) ,
47
- options . prettierOptions
32
+ options . tslintPath || getModulePath ( filePath , "tslint" )
48
33
) ;
49
34
50
35
const prettify = createPrettify (
51
- prettierOptions || fallbackPrettierOptions || { } ,
52
- prettierPath
36
+ options . prettierOptions || options . fallbackPrettierOptions || { } ,
37
+ options . prettierPath || getModulePath ( filePath , "prettier" )
53
38
) ;
54
- const tslintFix = createTSLintFix ( tslintConfig , tslintPath ) ;
55
39
56
- if ( prettierLast ) {
57
- return prettify ( tslintFix ( text , filePath ) ) ;
58
- }
59
- return tslintFix ( prettify ( text ) , filePath ) ;
40
+ const text = options . text || readFileSync ( filePath , "utf8" ) ;
41
+ return options . prettierLast
42
+ ? prettify ( tslintFix ( text , filePath ) , filePath )
43
+ : tslintFix ( prettify ( text , filePath ) , filePath ) ;
60
44
}
61
45
62
46
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
- }
47
+ const prettier = requireModule ( prettierPath ) ;
48
+ return function prettify ( text , filePath ) {
49
+ return prettier . format (
50
+ text ,
51
+ Object . assign (
52
+ { } ,
53
+ formatOptions ,
54
+ getPrettierConfig ( filePath ) ,
55
+ filePath && { filepath : filePath }
56
+ )
57
+ ) ;
71
58
} ;
72
59
}
73
60
74
- function createTSLintFix ( tslintConfig , tslintPath ) {
61
+ function createTSLintFix ( defaultLintConfig , tslintPath ) {
62
+ const tslint = requireModule ( tslintPath ) ;
63
+ const { findConfiguration } = tslint . Configuration ;
64
+
65
+ // Adapted from: https://github.com/palantir/tslint/blob/5.12.0/src/linter.ts
75
66
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
- } ) ;
67
+ // TODO: Use the "fix" option of `new tslint.Linter()` once the following
68
+ // issue is triaged: https://github.com/palantir/tslint/issues/4411
69
+ const linter = new tslint . Linter ( {
70
+ fix : false , // Disabled to avoid file operations.
71
+ formatter : "json" ,
72
+ } ) ;
73
+
74
+ const lintConfig = Object . assign (
75
+ { } ,
76
+ defaultLintConfig ,
77
+ findConfiguration ( null , filePath ) . results
78
+ ) ;
82
79
83
- linter . lint ( filePath , text , tslintConfig ) ;
84
- return applyTSLintAllFixes ( linter . getResult ( ) , text , tslint ) ;
85
- } catch ( error ) {
86
- throw error ;
80
+ linter . lint ( filePath , text , lintConfig ) ;
81
+ const { failures } = linter . getResult ( ) ;
82
+ if ( ! failures . length ) {
83
+ return text ;
87
84
}
88
- } ;
89
- }
90
85
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
- }
86
+ // This is a private method, but we're using it as a workaround.
87
+ const enabledRules = linter . getEnabledRules (
88
+ lintConfig ,
89
+ extname ( filePath ) === ".js"
90
+ ) ;
91
+
92
+ // To keep rules from interfering with one another, we apply their fixes one
93
+ // rule at a time. More info: https://github.com/azz/prettier-tslint/issues/26
94
+ return enabledRules . reduce ( ( text , rule ) => {
95
+ const { ruleName } = rule . getOptions ( ) ;
96
+ const hasFix = f => f . hasFix ( ) && f . getRuleName ( ) === ruleName ;
97
+ if ( failures . some ( hasFix ) ) {
98
+ const sourceFile = tslint . getSourceFile ( filePath , text ) ;
99
+ const fixableFailures = tslint
100
+ . removeDisabledFailures ( sourceFile , rule . apply ( sourceFile ) )
101
+ . filter ( f => f . hasFix ( ) ) ;
102
+
103
+ if ( fixableFailures . length ) {
104
+ const fixes = fixableFailures . map ( f => f . getFix ( ) ) ;
105
+ return tslint . Replacement . applyFixes ( text , fixes ) ;
106
+ }
107
+ }
108
+ return text ;
109
+ } , text ) ;
110
+ } ;
98
111
}
0 commit comments