/
config-file.js
143 lines (117 loc) · 4.44 KB
/
config-file.js
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* @fileoverview Helper to locate and load configuration files.
* @author Nicholas C. Zakas
*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import fs from "fs";
import path from "path";
import stringify from "json-stable-stringify-without-jsonify";
import debugEsm from "debug";
const debug = debugEsm("eslint:config-file");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Determines sort order for object keys for json-stable-stringify
*
* see: https://github.com/samn/json-stable-stringify#cmp
* @param {Object} a The first comparison object ({key: akey, value: avalue})
* @param {Object} b The second comparison object ({key: bkey, value: bvalue})
* @returns {number} 1 or -1, used in stringify cmp method
*/
function sortByKey(a, b) {
return a.key > b.key ? 1 : -1;
}
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
/**
* Writes a configuration file in JSON format.
* @param {Object} config The configuration object to write.
* @param {string} filePath The filename to write to.
* @returns {void}
* @private
*/
function writeJSONConfigFile(config, filePath) {
debug(`Writing JSON config file: ${filePath}`);
const content = `${stringify(config, { cmp: sortByKey, space: 4 })}\n`;
fs.writeFileSync(filePath, content, "utf8");
}
/**
* Writes a configuration file in YAML format.
* @param {Object} config The configuration object to write.
* @param {string} filePath The filename to write to.
* @returns {void}
* @private
*/
async function writeYAMLConfigFile(config, filePath) {
debug(`Writing YAML config file: ${filePath}`);
// TODO: cjs to esm
// lazy load YAML to improve performance when not used
const yaml = await import("js-yaml");
const content = yaml.dump(config, { sortKeys: true });
fs.writeFileSync(filePath, content, "utf8");
}
/**
* Writes a configuration file in JavaScript format.
* @param {Object} config The configuration object to write.
* @param {string} filePath The filename to write to.
* @throws {Error} If an error occurs linting the config file contents.
* @returns {void}
* @private
*/
async function writeJSConfigFile(config, filePath) {
debug(`Writing JS config file: ${filePath}`);
let contentToWrite;
const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};\n`;
try {
// TODO: cjs to esm
const ESLint = (await import("eslint")).default.ESLint;
const linter = new ESLint({ baseConfig: config, fix: true, useEslintrc: false });
const report = await linter.lintText(stringifiedContent);
contentToWrite = report[0].output || stringifiedContent;
} catch (e) {
debug("Error linting JavaScript config file, writing unlinted version");
const errorMessage = e.message;
contentToWrite = stringifiedContent;
e.message = "An error occurred while generating your JavaScript config file. ";
e.message += "A config file was still generated, but the config file itself may not follow your linting rules.";
e.message += `\nError: ${errorMessage}`;
throw e;
} finally {
fs.writeFileSync(filePath, contentToWrite, "utf8");
}
}
/**
* Writes a configuration file.
* @param {Object} config The configuration object to write.
* @param {string} filePath The filename to write to.
* @returns {void}
* @throws {Error} When an unknown file type is specified.
* @private
*/
async function write(config, filePath) {
switch (path.extname(filePath)) {
case ".js":
case ".cjs":
await writeJSConfigFile(config, filePath);
break;
case ".json":
writeJSONConfigFile(config, filePath);
break;
case ".yaml":
case ".yml":
await writeYAMLConfigFile(config, filePath);
break;
default:
throw new Error("Can't write to unknown file type.");
}
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
export {
write
};