-
Notifications
You must be signed in to change notification settings - Fork 205
/
format.ts
100 lines (94 loc) · 3.21 KB
/
format.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Options} from './cli';
import {createProgram} from './lint';
const clangFormat = require('clang-format');
const baseArgs = ['-style=file'];
/**
* Run tslint fix and clang fix with the default configuration
* @param options
* @param fix whether to automatically fix the format
* @param files files to format
*/
export async function format(
options: Options, files: string[] = [], fix = false): Promise<boolean> {
const program = createProgram(options);
// Obtain a list of source files to format.
// We use program.getRootFileNames to get only the files that match the
// include patterns specified in the given tsconfig.json file (as specified
// through options). This is necessary because we only want to format files
// over which the developer has control (i.e. not auto-generated or
// third-party source files).
const srcFiles = files.length > 0 ?
files :
program.getRootFileNames().filter(f => !f.endsWith('.d.ts'));
if (fix) {
return await fixFormat(srcFiles);
} else {
const result = await checkFormat(srcFiles);
if (!result) {
options.logger.log(
'clang-format reported errors... run `gts fix` to address.');
}
return result;
}
}
/**
* Runs clang-format to automatically fix the format of supplied files.
*
* @param srcFiles list of source files
*/
function fixFormat(srcFiles: string[]): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
const args = baseArgs.concat(['-i'], srcFiles);
clangFormat.spawnClangFormat(args, (err?: Error) => {
if (err) {
reject(err);
} else {
resolve(true);
}
}, 'inherit');
});
}
/**
* Runs clang-format on the list of files and checks whether they are formatted
* correctly. Returns true if all files are formatted correctly.
*
* @param srcFiles list of source files
*/
function checkFormat(srcFiles: string[]): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
let output = '';
const args = baseArgs.concat(['-output-replacements-xml'], srcFiles);
const out = clangFormat
.spawnClangFormat(
args,
(err?: Error) => {
if (err) {
reject(err);
}
},
['ignore', 'pipe', process.stderr])
.stdout;
out.setEncoding('utf8');
out.on('data', (data: Buffer) => {
output += data;
});
out.on('end', () => {
resolve(output.indexOf('<replacement ') === -1 ? true : false);
});
});
}