You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.4 KiB

4 years ago
  1. /**
  2. * @fileoverview Helper to locate and load configuration files.
  3. * @author Nicholas C. Zakas
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const fs = require("fs"),
  10. path = require("path"),
  11. stringify = require("json-stable-stringify-without-jsonify");
  12. const debug = require("debug")("eslint:config-file");
  13. //------------------------------------------------------------------------------
  14. // Helpers
  15. //------------------------------------------------------------------------------
  16. /**
  17. * Determines sort order for object keys for json-stable-stringify
  18. *
  19. * see: https://github.com/samn/json-stable-stringify#cmp
  20. * @param {Object} a The first comparison object ({key: akey, value: avalue})
  21. * @param {Object} b The second comparison object ({key: bkey, value: bvalue})
  22. * @returns {number} 1 or -1, used in stringify cmp method
  23. */
  24. function sortByKey(a, b) {
  25. return a.key > b.key ? 1 : -1;
  26. }
  27. //------------------------------------------------------------------------------
  28. // Private
  29. //------------------------------------------------------------------------------
  30. /**
  31. * Writes a configuration file in JSON format.
  32. * @param {Object} config The configuration object to write.
  33. * @param {string} filePath The filename to write to.
  34. * @returns {void}
  35. * @private
  36. */
  37. function writeJSONConfigFile(config, filePath) {
  38. debug(`Writing JSON config file: ${filePath}`);
  39. const content = `${stringify(config, { cmp: sortByKey, space: 4 })}\n`;
  40. fs.writeFileSync(filePath, content, "utf8");
  41. }
  42. /**
  43. * Writes a configuration file in YAML format.
  44. * @param {Object} config The configuration object to write.
  45. * @param {string} filePath The filename to write to.
  46. * @returns {void}
  47. * @private
  48. */
  49. function writeYAMLConfigFile(config, filePath) {
  50. debug(`Writing YAML config file: ${filePath}`);
  51. // lazy load YAML to improve performance when not used
  52. const yaml = require("js-yaml");
  53. const content = yaml.safeDump(config, { sortKeys: true });
  54. fs.writeFileSync(filePath, content, "utf8");
  55. }
  56. /**
  57. * Writes a configuration file in JavaScript format.
  58. * @param {Object} config The configuration object to write.
  59. * @param {string} filePath The filename to write to.
  60. * @throws {Error} If an error occurs linting the config file contents.
  61. * @returns {void}
  62. * @private
  63. */
  64. function writeJSConfigFile(config, filePath) {
  65. debug(`Writing JS config file: ${filePath}`);
  66. let contentToWrite;
  67. const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};\n`;
  68. try {
  69. const { CLIEngine } = require("../cli-engine");
  70. const linter = new CLIEngine({
  71. baseConfig: config,
  72. fix: true,
  73. useEslintrc: false
  74. });
  75. const report = linter.executeOnText(stringifiedContent);
  76. contentToWrite = report.results[0].output || stringifiedContent;
  77. } catch (e) {
  78. debug("Error linting JavaScript config file, writing unlinted version");
  79. const errorMessage = e.message;
  80. contentToWrite = stringifiedContent;
  81. e.message = "An error occurred while generating your JavaScript config file. ";
  82. e.message += "A config file was still generated, but the config file itself may not follow your linting rules.";
  83. e.message += `\nError: ${errorMessage}`;
  84. throw e;
  85. } finally {
  86. fs.writeFileSync(filePath, contentToWrite, "utf8");
  87. }
  88. }
  89. /**
  90. * Writes a configuration file.
  91. * @param {Object} config The configuration object to write.
  92. * @param {string} filePath The filename to write to.
  93. * @returns {void}
  94. * @throws {Error} When an unknown file type is specified.
  95. * @private
  96. */
  97. function write(config, filePath) {
  98. switch (path.extname(filePath)) {
  99. case ".js":
  100. writeJSConfigFile(config, filePath);
  101. break;
  102. case ".json":
  103. writeJSONConfigFile(config, filePath);
  104. break;
  105. case ".yaml":
  106. case ".yml":
  107. writeYAMLConfigFile(config, filePath);
  108. break;
  109. default:
  110. throw new Error("Can't write to unknown file type.");
  111. }
  112. }
  113. //------------------------------------------------------------------------------
  114. // Public Interface
  115. //------------------------------------------------------------------------------
  116. module.exports = {
  117. write
  118. };