版博士V2.0程序
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

313 строки
11 KiB

  1. /**
  2. * @fileoverview Compatibility class for flat config.
  3. * @author Nicholas C. Zakas
  4. */
  5. //-----------------------------------------------------------------------------
  6. // Requirements
  7. //-----------------------------------------------------------------------------
  8. import createDebug from "debug";
  9. import path from "path";
  10. import environments from "../conf/environments.js";
  11. import { ConfigArrayFactory } from "./config-array-factory.js";
  12. //-----------------------------------------------------------------------------
  13. // Helpers
  14. //-----------------------------------------------------------------------------
  15. /** @typedef {import("../../shared/types").Environment} Environment */
  16. /** @typedef {import("../../shared/types").Processor} Processor */
  17. const debug = createDebug("eslintrc:flat-compat");
  18. const cafactory = Symbol("cafactory");
  19. /**
  20. * Translates an ESLintRC-style config object into a flag-config-style config
  21. * object.
  22. * @param {Object} eslintrcConfig An ESLintRC-style config object.
  23. * @param {Object} options Options to help translate the config.
  24. * @param {string} options.resolveConfigRelativeTo To the directory to resolve
  25. * configs from.
  26. * @param {string} options.resolvePluginsRelativeTo The directory to resolve
  27. * plugins from.
  28. * @param {ReadOnlyMap<string,Environment>} options.pluginEnvironments A map of plugin environment
  29. * names to objects.
  30. * @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
  31. * names to objects.
  32. * @returns {Object} A flag-config-style config object.
  33. */
  34. function translateESLintRC(eslintrcConfig, {
  35. resolveConfigRelativeTo,
  36. resolvePluginsRelativeTo,
  37. pluginEnvironments,
  38. pluginProcessors
  39. }) {
  40. const flatConfig = {};
  41. const configs = [];
  42. const languageOptions = {};
  43. const linterOptions = {};
  44. const keysToCopy = ["settings", "rules", "processor"];
  45. const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
  46. const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
  47. // copy over simple translations
  48. for (const key of keysToCopy) {
  49. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  50. flatConfig[key] = eslintrcConfig[key];
  51. }
  52. }
  53. // copy over languageOptions
  54. for (const key of languageOptionsKeysToCopy) {
  55. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  56. // create the languageOptions key in the flat config
  57. flatConfig.languageOptions = languageOptions;
  58. if (key === "parser") {
  59. debug(`Resolving parser '${languageOptions[key]}' relative to ${resolveConfigRelativeTo}`);
  60. if (eslintrcConfig[key].error) {
  61. throw eslintrcConfig[key].error;
  62. }
  63. languageOptions[key] = eslintrcConfig[key].definition;
  64. continue;
  65. }
  66. // clone any object values that are in the eslintrc config
  67. if (eslintrcConfig[key] && typeof eslintrcConfig[key] === "object") {
  68. languageOptions[key] = {
  69. ...eslintrcConfig[key]
  70. };
  71. } else {
  72. languageOptions[key] = eslintrcConfig[key];
  73. }
  74. }
  75. }
  76. // copy over linterOptions
  77. for (const key of linterOptionsKeysToCopy) {
  78. if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
  79. flatConfig.linterOptions = linterOptions;
  80. linterOptions[key] = eslintrcConfig[key];
  81. }
  82. }
  83. // move ecmaVersion a level up
  84. if (languageOptions.parserOptions) {
  85. if ("ecmaVersion" in languageOptions.parserOptions) {
  86. languageOptions.ecmaVersion = languageOptions.parserOptions.ecmaVersion;
  87. delete languageOptions.parserOptions.ecmaVersion;
  88. }
  89. if ("sourceType" in languageOptions.parserOptions) {
  90. languageOptions.sourceType = languageOptions.parserOptions.sourceType;
  91. delete languageOptions.parserOptions.sourceType;
  92. }
  93. // check to see if we even need parserOptions anymore and remove it if not
  94. if (Object.keys(languageOptions.parserOptions).length === 0) {
  95. delete languageOptions.parserOptions;
  96. }
  97. }
  98. // overrides
  99. if (eslintrcConfig.criteria) {
  100. flatConfig.files = [absoluteFilePath => eslintrcConfig.criteria.test(absoluteFilePath)];
  101. }
  102. // translate plugins
  103. if (eslintrcConfig.plugins && typeof eslintrcConfig.plugins === "object") {
  104. debug(`Translating plugins: ${eslintrcConfig.plugins}`);
  105. flatConfig.plugins = {};
  106. for (const pluginName of Object.keys(eslintrcConfig.plugins)) {
  107. debug(`Translating plugin: ${pluginName}`);
  108. debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
  109. const { definition: plugin, error } = eslintrcConfig.plugins[pluginName];
  110. if (error) {
  111. throw error;
  112. }
  113. flatConfig.plugins[pluginName] = plugin;
  114. // create a config for any processors
  115. if (plugin.processors) {
  116. for (const processorName of Object.keys(plugin.processors)) {
  117. if (processorName.startsWith(".")) {
  118. debug(`Assigning processor: ${pluginName}/${processorName}`);
  119. configs.unshift({
  120. files: [`**/*${processorName}`],
  121. processor: pluginProcessors.get(`${pluginName}/${processorName}`)
  122. });
  123. }
  124. }
  125. }
  126. }
  127. }
  128. // translate env - must come after plugins
  129. if (eslintrcConfig.env && typeof eslintrcConfig.env === "object") {
  130. for (const envName of Object.keys(eslintrcConfig.env)) {
  131. // only add environments that are true
  132. if (eslintrcConfig.env[envName]) {
  133. debug(`Translating environment: ${envName}`);
  134. if (environments.has(envName)) {
  135. // built-in environments should be defined first
  136. configs.unshift(...translateESLintRC(environments.get(envName), {
  137. resolveConfigRelativeTo,
  138. resolvePluginsRelativeTo
  139. }));
  140. } else if (pluginEnvironments.has(envName)) {
  141. // if the environment comes from a plugin, it should come after the plugin config
  142. configs.push(...translateESLintRC(pluginEnvironments.get(envName), {
  143. resolveConfigRelativeTo,
  144. resolvePluginsRelativeTo
  145. }));
  146. }
  147. }
  148. }
  149. }
  150. // only add if there are actually keys in the config
  151. if (Object.keys(flatConfig).length > 0) {
  152. configs.push(flatConfig);
  153. }
  154. return configs;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Exports
  158. //-----------------------------------------------------------------------------
  159. /**
  160. * A compatibility class for working with configs.
  161. */
  162. class FlatCompat {
  163. constructor({
  164. baseDirectory = process.cwd(),
  165. resolvePluginsRelativeTo = baseDirectory,
  166. recommendedConfig,
  167. allConfig
  168. } = {}) {
  169. this.baseDirectory = baseDirectory;
  170. this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
  171. this[cafactory] = new ConfigArrayFactory({
  172. cwd: baseDirectory,
  173. resolvePluginsRelativeTo,
  174. getEslintAllConfig: () => {
  175. if (!allConfig) {
  176. throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor.");
  177. }
  178. return allConfig;
  179. },
  180. getEslintRecommendedConfig: () => {
  181. if (!recommendedConfig) {
  182. throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor.");
  183. }
  184. return recommendedConfig;
  185. }
  186. });
  187. }
  188. /**
  189. * Translates an ESLintRC-style config into a flag-config-style config.
  190. * @param {Object} eslintrcConfig The ESLintRC-style config object.
  191. * @returns {Object} A flag-config-style config object.
  192. */
  193. config(eslintrcConfig) {
  194. const eslintrcArray = this[cafactory].create(eslintrcConfig, {
  195. basePath: this.baseDirectory
  196. });
  197. const flatArray = [];
  198. let hasIgnorePatterns = false;
  199. eslintrcArray.forEach(configData => {
  200. if (configData.type === "config") {
  201. hasIgnorePatterns = hasIgnorePatterns || configData.ignorePattern;
  202. flatArray.push(...translateESLintRC(configData, {
  203. resolveConfigRelativeTo: path.join(this.baseDirectory, "__placeholder.js"),
  204. resolvePluginsRelativeTo: path.join(this.resolvePluginsRelativeTo, "__placeholder.js"),
  205. pluginEnvironments: eslintrcArray.pluginEnvironments,
  206. pluginProcessors: eslintrcArray.pluginProcessors
  207. }));
  208. }
  209. });
  210. // combine ignorePatterns to emulate ESLintRC behavior better
  211. if (hasIgnorePatterns) {
  212. flatArray.unshift({
  213. ignores: [filePath => {
  214. // Compute the final config for this file.
  215. // This filters config array elements by `files`/`excludedFiles` then merges the elements.
  216. const finalConfig = eslintrcArray.extractConfig(filePath);
  217. // Test the `ignorePattern` properties of the final config.
  218. return Boolean(finalConfig.ignores) && finalConfig.ignores(filePath);
  219. }]
  220. });
  221. }
  222. return flatArray;
  223. }
  224. /**
  225. * Translates the `env` section of an ESLintRC-style config.
  226. * @param {Object} envConfig The `env` section of an ESLintRC config.
  227. * @returns {Object[]} An array of flag-config objects representing the environments.
  228. */
  229. env(envConfig) {
  230. return this.config({
  231. env: envConfig
  232. });
  233. }
  234. /**
  235. * Translates the `extends` section of an ESLintRC-style config.
  236. * @param {...string} configsToExtend The names of the configs to load.
  237. * @returns {Object[]} An array of flag-config objects representing the config.
  238. */
  239. extends(...configsToExtend) {
  240. return this.config({
  241. extends: configsToExtend
  242. });
  243. }
  244. /**
  245. * Translates the `plugins` section of an ESLintRC-style config.
  246. * @param {...string} plugins The names of the plugins to load.
  247. * @returns {Object[]} An array of flag-config objects representing the plugins.
  248. */
  249. plugins(...plugins) {
  250. return this.config({
  251. plugins
  252. });
  253. }
  254. }
  255. export { FlatCompat };