Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 1 | 'use strict'; |
| 2 | |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 3 | const configurationError = require('./utils/configurationError'); |
| 4 | const getModulePath = require('./utils/getModulePath'); |
| 5 | const globjoin = require('globjoin'); |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 6 | const micromatch = require('micromatch'); |
Tim van der Lippe | efb716a | 2020-12-01 12:54:04 +0000 | [diff] [blame] | 7 | const normalizeAllRuleSettings = require('./normalizeAllRuleSettings'); |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 8 | const normalizePath = require('normalize-path'); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 9 | const path = require('path'); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 10 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 11 | /** @typedef {import('stylelint').ConfigPlugins} StylelintConfigPlugins */ |
| 12 | /** @typedef {import('stylelint').ConfigProcessor} StylelintConfigProcessor */ |
| 13 | /** @typedef {import('stylelint').ConfigProcessors} StylelintConfigProcessors */ |
| 14 | /** @typedef {import('stylelint').ConfigRules} StylelintConfigRules */ |
| 15 | /** @typedef {import('stylelint').ConfigOverride} StylelintConfigOverride */ |
| 16 | /** @typedef {import('stylelint').InternalApi} StylelintInternalApi */ |
| 17 | /** @typedef {import('stylelint').Config} StylelintConfig */ |
| 18 | /** @typedef {import('stylelint').CosmiconfigResult} StylelintCosmiconfigResult */ |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 19 | |
| 20 | /** |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 21 | * - Merges config and stylelint options |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 22 | * - Makes all paths absolute |
| 23 | * - Merges extends |
| 24 | * @param {StylelintInternalApi} stylelint |
| 25 | * @param {StylelintConfig} config |
| 26 | * @param {string} configDir |
| 27 | * @param {boolean} [allowOverrides] |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 28 | * @param {string} [filePath] |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 29 | * @returns {Promise<StylelintConfig>} |
| 30 | */ |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 31 | async function augmentConfigBasic(stylelint, config, configDir, allowOverrides, filePath) { |
| 32 | let augmentedConfig = config; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 33 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 34 | if (allowOverrides) { |
| 35 | augmentedConfig = addOptions(stylelint, augmentedConfig); |
| 36 | } |
| 37 | |
| 38 | augmentedConfig = await extendConfig(stylelint, augmentedConfig, configDir); |
| 39 | |
| 40 | if (filePath) { |
| 41 | while (augmentedConfig.overrides) { |
| 42 | augmentedConfig = applyOverrides(augmentedConfig, configDir, filePath); |
| 43 | augmentedConfig = await extendConfig(stylelint, augmentedConfig, configDir); |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | return absolutizePaths(augmentedConfig, configDir); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Extended configs need to be run through augmentConfigBasic |
| 52 | * but do not need the full treatment. Things like pluginFunctions |
| 53 | * will be resolved and added by the parent config. |
| 54 | * @param {StylelintInternalApi} stylelint |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 55 | * @param {StylelintCosmiconfigResult} [cosmiconfigResult] |
| 56 | * @returns {Promise<StylelintCosmiconfigResult>} |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 57 | */ |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 58 | async function augmentConfigExtended(stylelint, cosmiconfigResult) { |
| 59 | if (!cosmiconfigResult) { |
| 60 | return null; |
| 61 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 62 | |
| 63 | const configDir = path.dirname(cosmiconfigResult.filepath || ''); |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 64 | const { config } = cosmiconfigResult; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 65 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 66 | const augmentedConfig = await augmentConfigBasic(stylelint, config, configDir); |
| 67 | |
| 68 | return { |
| 69 | config: augmentedConfig, |
| 70 | filepath: cosmiconfigResult.filepath, |
| 71 | }; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | /** |
| 75 | * @param {StylelintInternalApi} stylelint |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 76 | * @param {string} [filePath] |
| 77 | * @param {StylelintCosmiconfigResult} [cosmiconfigResult] |
| 78 | * @returns {Promise<StylelintCosmiconfigResult>} |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 79 | */ |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 80 | async function augmentConfigFull(stylelint, filePath, cosmiconfigResult) { |
| 81 | if (!cosmiconfigResult) { |
| 82 | return null; |
| 83 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 84 | |
| 85 | const config = cosmiconfigResult.config; |
| 86 | const filepath = cosmiconfigResult.filepath; |
| 87 | |
| 88 | const configDir = stylelint._options.configBasedir || path.dirname(filepath || ''); |
| 89 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 90 | let augmentedConfig = await augmentConfigBasic(stylelint, config, configDir, true, filePath); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 91 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 92 | augmentedConfig = addPluginFunctions(augmentedConfig); |
| 93 | augmentedConfig = addProcessorFunctions(augmentedConfig); |
| 94 | |
| 95 | if (!augmentedConfig.rules) { |
| 96 | throw configurationError( |
| 97 | 'No rules found within configuration. Have you provided a "rules" property?', |
| 98 | ); |
| 99 | } |
| 100 | |
| 101 | augmentedConfig = normalizeAllRuleSettings(augmentedConfig); |
| 102 | |
| 103 | return { |
| 104 | config: augmentedConfig, |
| 105 | filepath: cosmiconfigResult.filepath, |
| 106 | }; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | /** |
| 110 | * Make all paths in the config absolute: |
| 111 | * - ignoreFiles |
| 112 | * - plugins |
| 113 | * - processors |
| 114 | * (extends handled elsewhere) |
| 115 | * @param {StylelintConfig} config |
| 116 | * @param {string} configDir |
| 117 | * @returns {StylelintConfig} |
| 118 | */ |
| 119 | function absolutizePaths(config, configDir) { |
| 120 | if (config.ignoreFiles) { |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 121 | config.ignoreFiles = [config.ignoreFiles].flat().map((glob) => { |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 122 | if (path.isAbsolute(glob.replace(/^!/, ''))) return glob; |
| 123 | |
| 124 | return globjoin(configDir, glob); |
| 125 | }); |
| 126 | } |
| 127 | |
| 128 | if (config.plugins) { |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 129 | config.plugins = [config.plugins].flat().map((lookup) => getModulePath(configDir, lookup)); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | if (config.processors) { |
| 133 | config.processors = absolutizeProcessors(config.processors, configDir); |
| 134 | } |
| 135 | |
| 136 | return config; |
| 137 | } |
| 138 | |
| 139 | /** |
| 140 | * Processors are absolutized in their own way because |
| 141 | * they can be and return a string or an array |
| 142 | * @param {StylelintConfigProcessors} processors |
| 143 | * @param {string} configDir |
| 144 | * @return {StylelintConfigProcessors} |
| 145 | */ |
| 146 | function absolutizeProcessors(processors, configDir) { |
| 147 | const normalizedProcessors = Array.isArray(processors) ? processors : [processors]; |
| 148 | |
| 149 | return normalizedProcessors.map((item) => { |
| 150 | if (typeof item === 'string') { |
| 151 | return getModulePath(configDir, item); |
| 152 | } |
| 153 | |
| 154 | return [getModulePath(configDir, item[0]), item[1]]; |
| 155 | }); |
| 156 | } |
| 157 | |
| 158 | /** |
| 159 | * @param {StylelintInternalApi} stylelint |
| 160 | * @param {StylelintConfig} config |
| 161 | * @param {string} configDir |
| 162 | * @return {Promise<StylelintConfig>} |
| 163 | */ |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 164 | async function extendConfig(stylelint, config, configDir) { |
| 165 | if (config.extends === undefined) { |
| 166 | return config; |
| 167 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 168 | |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 169 | const { extends: configExtends, ...originalWithoutExtends } = config; |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 170 | const normalizedExtends = [configExtends].flat(); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 171 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 172 | let resultConfig = originalWithoutExtends; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 173 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 174 | for (const extendLookup of normalizedExtends) { |
| 175 | const extendResult = await loadExtendedConfig(stylelint, configDir, extendLookup); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 176 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 177 | if (extendResult) { |
| 178 | resultConfig = mergeConfigs(resultConfig, extendResult.config); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | return mergeConfigs(resultConfig, originalWithoutExtends); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | /** |
| 186 | * @param {StylelintInternalApi} stylelint |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 187 | * @param {string} configDir |
| 188 | * @param {string} extendLookup |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 189 | * @return {Promise<StylelintCosmiconfigResult>} |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 190 | */ |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 191 | function loadExtendedConfig(stylelint, configDir, extendLookup) { |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 192 | const extendPath = getModulePath(configDir, extendLookup); |
| 193 | |
| 194 | return stylelint._extendExplorer.load(extendPath); |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * When merging configs (via extends) |
| 199 | * - plugin and processor arrays are joined |
| 200 | * - rules are merged via Object.assign, so there is no attempt made to |
| 201 | * merge any given rule's settings. If b contains the same rule as a, |
| 202 | * b's rule settings will override a's rule settings entirely. |
| 203 | * - Everything else is merged via Object.assign |
| 204 | * @param {StylelintConfig} a |
| 205 | * @param {StylelintConfig} b |
| 206 | * @returns {StylelintConfig} |
| 207 | */ |
| 208 | function mergeConfigs(a, b) { |
| 209 | /** @type {{plugins: StylelintConfigPlugins}} */ |
| 210 | const pluginMerger = {}; |
| 211 | |
| 212 | if (a.plugins || b.plugins) { |
| 213 | pluginMerger.plugins = []; |
| 214 | |
| 215 | if (a.plugins) { |
| 216 | pluginMerger.plugins = pluginMerger.plugins.concat(a.plugins); |
| 217 | } |
| 218 | |
| 219 | if (b.plugins) { |
| 220 | pluginMerger.plugins = [...new Set(pluginMerger.plugins.concat(b.plugins))]; |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | /** @type {{processors: StylelintConfigProcessors}} */ |
| 225 | const processorMerger = {}; |
| 226 | |
| 227 | if (a.processors || b.processors) { |
| 228 | processorMerger.processors = []; |
| 229 | |
| 230 | if (a.processors) { |
| 231 | processorMerger.processors = processorMerger.processors.concat(a.processors); |
| 232 | } |
| 233 | |
| 234 | if (b.processors) { |
| 235 | processorMerger.processors = [...new Set(processorMerger.processors.concat(b.processors))]; |
| 236 | } |
| 237 | } |
| 238 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 239 | /** @type {{overrides: StylelintConfigOverride[]}} */ |
| 240 | const overridesMerger = {}; |
| 241 | |
| 242 | if (a.overrides || b.overrides) { |
| 243 | overridesMerger.overrides = []; |
| 244 | |
| 245 | if (a.overrides) { |
| 246 | overridesMerger.overrides = overridesMerger.overrides.concat(a.overrides); |
| 247 | } |
| 248 | |
| 249 | if (b.overrides) { |
| 250 | overridesMerger.overrides = [...new Set(overridesMerger.overrides.concat(b.overrides))]; |
| 251 | } |
| 252 | } |
| 253 | |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 254 | const rulesMerger = {}; |
| 255 | |
| 256 | if (a.rules || b.rules) { |
| 257 | rulesMerger.rules = { ...a.rules, ...b.rules }; |
| 258 | } |
| 259 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 260 | const result = { |
| 261 | ...a, |
| 262 | ...b, |
| 263 | ...processorMerger, |
| 264 | ...pluginMerger, |
| 265 | ...overridesMerger, |
| 266 | ...rulesMerger, |
| 267 | }; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 268 | |
| 269 | return result; |
| 270 | } |
| 271 | |
| 272 | /** |
| 273 | * @param {StylelintConfig} config |
| 274 | * @returns {StylelintConfig} |
| 275 | */ |
| 276 | function addPluginFunctions(config) { |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 277 | if (!config.plugins) { |
| 278 | return config; |
| 279 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 280 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 281 | const normalizedPlugins = [config.plugins].flat(); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 282 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 283 | /** @type {{[k: string]: Function}} */ |
| 284 | const pluginFunctions = {}; |
| 285 | |
| 286 | for (const pluginLookup of normalizedPlugins) { |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 287 | let pluginImport = require(pluginLookup); |
| 288 | |
| 289 | // Handle either ES6 or CommonJS modules |
| 290 | pluginImport = pluginImport.default || pluginImport; |
| 291 | |
| 292 | // A plugin can export either a single rule definition |
| 293 | // or an array of them |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 294 | const normalizedPluginImport = [pluginImport].flat(); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 295 | |
| 296 | normalizedPluginImport.forEach((pluginRuleDefinition) => { |
| 297 | if (!pluginRuleDefinition.ruleName) { |
| 298 | throw configurationError( |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 299 | `stylelint requires plugins to expose a ruleName. The plugin "${pluginLookup}" is not doing this, so will not work with stylelint. Please file an issue with the plugin.`, |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 300 | ); |
| 301 | } |
| 302 | |
| 303 | if (!pluginRuleDefinition.ruleName.includes('/')) { |
| 304 | throw configurationError( |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 305 | `stylelint requires plugin rules to be namespaced, i.e. only \`plugin-namespace/plugin-rule-name\` plugin rule names are supported. The plugin rule "${pluginRuleDefinition.ruleName}" does not do this, so will not work. Please file an issue with the plugin.`, |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 306 | ); |
| 307 | } |
| 308 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 309 | pluginFunctions[pluginRuleDefinition.ruleName] = pluginRuleDefinition.rule; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 310 | }); |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 311 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 312 | |
| 313 | config.pluginFunctions = pluginFunctions; |
| 314 | |
| 315 | return config; |
| 316 | } |
| 317 | |
| 318 | /** |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 319 | * Given an array of processors strings, we want to add two |
| 320 | * properties to the augmented config: |
| 321 | * - codeProcessors: functions that will run on code as it comes in |
| 322 | * - resultProcessors: functions that will run on results as they go out |
| 323 | * |
| 324 | * To create these properties, we need to: |
| 325 | * - Find the processor module |
| 326 | * - Initialize the processor module by calling its functions with any |
| 327 | * provided options |
| 328 | * - Push the processor's code and result processors to their respective arrays |
| 329 | * @type {Map<string, string | Object>} |
| 330 | */ |
| 331 | const processorCache = new Map(); |
| 332 | |
| 333 | /** |
| 334 | * @param {StylelintConfig} config |
| 335 | * @return {StylelintConfig} |
| 336 | */ |
| 337 | function addProcessorFunctions(config) { |
| 338 | if (!config.processors) return config; |
| 339 | |
| 340 | /** @type {Array<Function>} */ |
| 341 | const codeProcessors = []; |
| 342 | /** @type {Array<Function>} */ |
| 343 | const resultProcessors = []; |
| 344 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 345 | [config.processors].flat().forEach((processorConfig) => { |
| 346 | const processorKey = JSON.stringify(processorConfig); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 347 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 348 | let initializedProcessor; |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 349 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 350 | if (processorCache.has(processorKey)) { |
| 351 | initializedProcessor = processorCache.get(processorKey); |
| 352 | } else { |
| 353 | const processorLookup = |
| 354 | typeof processorConfig === 'string' ? processorConfig : processorConfig[0]; |
| 355 | const processorOptions = typeof processorConfig === 'string' ? undefined : processorConfig[1]; |
| 356 | let processor = require(processorLookup); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 357 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 358 | processor = processor.default || processor; |
| 359 | initializedProcessor = processor(processorOptions); |
| 360 | processorCache.set(processorKey, initializedProcessor); |
| 361 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 362 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 363 | if (initializedProcessor && initializedProcessor.code) { |
| 364 | codeProcessors.push(initializedProcessor.code); |
| 365 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 366 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 367 | if (initializedProcessor && initializedProcessor.result) { |
| 368 | resultProcessors.push(initializedProcessor.result); |
| 369 | } |
| 370 | }); |
Mathias Bynens | 79e2cf0 | 2020-05-29 16:46:17 +0200 | [diff] [blame] | 371 | |
| 372 | config.codeProcessors = codeProcessors; |
| 373 | config.resultProcessors = resultProcessors; |
| 374 | |
| 375 | return config; |
| 376 | } |
| 377 | |
Tim van der Lippe | 16b8228 | 2021-11-08 13:50:26 +0000 | [diff] [blame^] | 378 | /** |
| 379 | * @param {StylelintConfig} fullConfig |
| 380 | * @param {string} configDir |
| 381 | * @param {string} filePath |
| 382 | * @return {StylelintConfig} |
| 383 | */ |
| 384 | function applyOverrides(fullConfig, configDir, filePath) { |
| 385 | let { overrides, ...config } = fullConfig; |
| 386 | |
| 387 | if (!overrides) { |
| 388 | return config; |
| 389 | } |
| 390 | |
| 391 | if (!Array.isArray(overrides)) { |
| 392 | throw new TypeError( |
| 393 | 'The `overrides` configuration property should be an array, e.g. { "overrides": [{ "files": "*.css", "rules": {} }] }.', |
| 394 | ); |
| 395 | } |
| 396 | |
| 397 | for (const override of overrides) { |
| 398 | const { files, ...configOverrides } = override; |
| 399 | |
| 400 | if (!files) { |
| 401 | throw new Error( |
| 402 | 'Every object in the `overrides` configuration property should have a `files` property with globs, e.g. { "overrides": [{ "files": "*.css", "rules": {} }] }.', |
| 403 | ); |
| 404 | } |
| 405 | |
| 406 | const filesGlobs = [files] |
| 407 | .flat() |
| 408 | .map((glob) => { |
| 409 | if (path.isAbsolute(glob.replace(/^!/, ''))) { |
| 410 | return glob; |
| 411 | } |
| 412 | |
| 413 | return globjoin(configDir, glob); |
| 414 | }) |
| 415 | // Glob patterns for micromatch should be in POSIX-style |
| 416 | .map((s) => normalizePath(s)); |
| 417 | |
| 418 | if (micromatch.isMatch(filePath, filesGlobs, { dot: true })) { |
| 419 | config = mergeConfigs(config, configOverrides); |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | return config; |
| 424 | } |
| 425 | |
| 426 | /** |
| 427 | * Add options to the config |
| 428 | * |
| 429 | * @param {StylelintInternalApi} stylelint |
| 430 | * @param {StylelintConfig} config |
| 431 | * |
| 432 | * @returns {StylelintConfig} |
| 433 | */ |
| 434 | function addOptions(stylelint, config) { |
| 435 | const augmentedConfig = { |
| 436 | ...config, |
| 437 | }; |
| 438 | |
| 439 | if (stylelint._options.ignoreDisables) { |
| 440 | augmentedConfig.ignoreDisables = stylelint._options.ignoreDisables; |
| 441 | } |
| 442 | |
| 443 | if (stylelint._options.quiet) { |
| 444 | augmentedConfig.quiet = stylelint._options.quiet; |
| 445 | } |
| 446 | |
| 447 | if (stylelint._options.reportNeedlessDisables) { |
| 448 | augmentedConfig.reportNeedlessDisables = stylelint._options.reportNeedlessDisables; |
| 449 | } |
| 450 | |
| 451 | if (stylelint._options.reportInvalidScopeDisables) { |
| 452 | augmentedConfig.reportInvalidScopeDisables = stylelint._options.reportInvalidScopeDisables; |
| 453 | } |
| 454 | |
| 455 | if (stylelint._options.reportDescriptionlessDisables) { |
| 456 | augmentedConfig.reportDescriptionlessDisables = |
| 457 | stylelint._options.reportDescriptionlessDisables; |
| 458 | } |
| 459 | |
| 460 | if (stylelint._options.customSyntax) { |
| 461 | augmentedConfig.customSyntax = stylelint._options.customSyntax; |
| 462 | } |
| 463 | |
| 464 | return augmentedConfig; |
| 465 | } |
| 466 | |
| 467 | module.exports = { augmentConfigExtended, augmentConfigFull, applyOverrides }; |