Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
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.

augmentConfig.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. 'use strict';
  2. const _ = require('lodash');
  3. const configurationError = require('./utils/configurationError');
  4. const getModulePath = require('./utils/getModulePath');
  5. const globjoin = require('globjoin');
  6. const normalizeAllRuleSettings = require('./normalizeAllRuleSettings');
  7. const path = require('path');
  8. /** @typedef {import('stylelint').StylelintConfigPlugins} StylelintConfigPlugins */
  9. /** @typedef {import('stylelint').StylelintConfigProcessor} StylelintConfigProcessor */
  10. /** @typedef {import('stylelint').StylelintConfigProcessors} StylelintConfigProcessors */
  11. /** @typedef {import('stylelint').StylelintConfigRules} StylelintConfigRules */
  12. /** @typedef {import('stylelint').StylelintInternalApi} StylelintInternalApi */
  13. /** @typedef {import('stylelint').StylelintConfig} StylelintConfig */
  14. /** @typedef {import('stylelint').CosmiconfigResult} CosmiconfigResult */
  15. /**
  16. * - Merges config and configOverrides
  17. * - Makes all paths absolute
  18. * - Merges extends
  19. * @param {StylelintInternalApi} stylelint
  20. * @param {StylelintConfig} config
  21. * @param {string} configDir
  22. * @param {boolean} [allowOverrides]
  23. * @returns {Promise<StylelintConfig>}
  24. */
  25. function augmentConfigBasic(stylelint, config, configDir, allowOverrides) {
  26. return Promise.resolve()
  27. .then(() => {
  28. if (!allowOverrides) return config;
  29. return _.merge(config, stylelint._options.configOverrides);
  30. })
  31. .then((augmentedConfig) => {
  32. return extendConfig(stylelint, augmentedConfig, configDir);
  33. })
  34. .then((augmentedConfig) => {
  35. return absolutizePaths(augmentedConfig, configDir);
  36. });
  37. }
  38. /**
  39. * Extended configs need to be run through augmentConfigBasic
  40. * but do not need the full treatment. Things like pluginFunctions
  41. * will be resolved and added by the parent config.
  42. * @param {StylelintInternalApi} stylelint
  43. * @param {CosmiconfigResult} [cosmiconfigResult]
  44. * @returns {Promise<CosmiconfigResult | null>}
  45. */
  46. function augmentConfigExtended(stylelint, cosmiconfigResult) {
  47. if (!cosmiconfigResult) return Promise.resolve(null);
  48. const configDir = path.dirname(cosmiconfigResult.filepath || '');
  49. const { ignoreFiles, ...cleanedConfig } = cosmiconfigResult.config;
  50. return augmentConfigBasic(stylelint, cleanedConfig, configDir).then((augmentedConfig) => {
  51. return {
  52. config: augmentedConfig,
  53. filepath: cosmiconfigResult.filepath,
  54. };
  55. });
  56. }
  57. /**
  58. * @param {StylelintInternalApi} stylelint
  59. * @param {CosmiconfigResult} [cosmiconfigResult]
  60. * @returns {Promise<CosmiconfigResult | null>}
  61. */
  62. function augmentConfigFull(stylelint, cosmiconfigResult) {
  63. if (!cosmiconfigResult) return Promise.resolve(null);
  64. const config = cosmiconfigResult.config;
  65. const filepath = cosmiconfigResult.filepath;
  66. const configDir = stylelint._options.configBasedir || path.dirname(filepath || '');
  67. return augmentConfigBasic(stylelint, config, configDir, true)
  68. .then((augmentedConfig) => {
  69. return addPluginFunctions(augmentedConfig);
  70. })
  71. .then((augmentedConfig) => {
  72. return addProcessorFunctions(augmentedConfig);
  73. })
  74. .then((augmentedConfig) => {
  75. if (!augmentedConfig.rules) {
  76. throw configurationError(
  77. 'No rules found within configuration. Have you provided a "rules" property?',
  78. );
  79. }
  80. return normalizeAllRuleSettings(augmentedConfig);
  81. })
  82. .then((augmentedConfig) => {
  83. return {
  84. config: augmentedConfig,
  85. filepath: cosmiconfigResult.filepath,
  86. };
  87. });
  88. }
  89. /**
  90. * Make all paths in the config absolute:
  91. * - ignoreFiles
  92. * - plugins
  93. * - processors
  94. * (extends handled elsewhere)
  95. * @param {StylelintConfig} config
  96. * @param {string} configDir
  97. * @returns {StylelintConfig}
  98. */
  99. function absolutizePaths(config, configDir) {
  100. if (config.ignoreFiles) {
  101. config.ignoreFiles = /** @type {string[]} */ ([]).concat(config.ignoreFiles).map((glob) => {
  102. if (path.isAbsolute(glob.replace(/^!/, ''))) return glob;
  103. return globjoin(configDir, glob);
  104. });
  105. }
  106. if (config.plugins) {
  107. config.plugins = /** @type {string[]} */ ([]).concat(config.plugins).map((lookup) => {
  108. return getModulePath(configDir, lookup);
  109. });
  110. }
  111. if (config.processors) {
  112. config.processors = absolutizeProcessors(config.processors, configDir);
  113. }
  114. return config;
  115. }
  116. /**
  117. * Processors are absolutized in their own way because
  118. * they can be and return a string or an array
  119. * @param {StylelintConfigProcessors} processors
  120. * @param {string} configDir
  121. * @return {StylelintConfigProcessors}
  122. */
  123. function absolutizeProcessors(processors, configDir) {
  124. const normalizedProcessors = Array.isArray(processors) ? processors : [processors];
  125. return normalizedProcessors.map((item) => {
  126. if (typeof item === 'string') {
  127. return getModulePath(configDir, item);
  128. }
  129. return [getModulePath(configDir, item[0]), item[1]];
  130. });
  131. }
  132. /**
  133. * @param {StylelintInternalApi} stylelint
  134. * @param {StylelintConfig} config
  135. * @param {string} configDir
  136. * @return {Promise<StylelintConfig>}
  137. */
  138. function extendConfig(stylelint, config, configDir) {
  139. if (config.extends === undefined) return Promise.resolve(config);
  140. const normalizedExtends = Array.isArray(config.extends) ? config.extends : [config.extends];
  141. const { extends: configExtends, ...originalWithoutExtends } = config;
  142. const loadExtends = normalizedExtends.reduce((resultPromise, extendLookup) => {
  143. return resultPromise.then((resultConfig) => {
  144. return loadExtendedConfig(stylelint, resultConfig, configDir, extendLookup).then(
  145. (extendResult) => {
  146. if (!extendResult) return resultConfig;
  147. return mergeConfigs(resultConfig, extendResult.config);
  148. },
  149. );
  150. });
  151. }, Promise.resolve(originalWithoutExtends));
  152. return loadExtends.then((resultConfig) => {
  153. return mergeConfigs(resultConfig, originalWithoutExtends);
  154. });
  155. }
  156. /**
  157. * @param {StylelintInternalApi} stylelint
  158. * @param {StylelintConfig} config
  159. * @param {string} configDir
  160. * @param {string} extendLookup
  161. * @return {Promise<CosmiconfigResult | null>}
  162. */
  163. function loadExtendedConfig(stylelint, config, configDir, extendLookup) {
  164. const extendPath = getModulePath(configDir, extendLookup);
  165. return stylelint._extendExplorer.load(extendPath);
  166. }
  167. /**
  168. * When merging configs (via extends)
  169. * - plugin and processor arrays are joined
  170. * - rules are merged via Object.assign, so there is no attempt made to
  171. * merge any given rule's settings. If b contains the same rule as a,
  172. * b's rule settings will override a's rule settings entirely.
  173. * - Everything else is merged via Object.assign
  174. * @param {StylelintConfig} a
  175. * @param {StylelintConfig} b
  176. * @returns {StylelintConfig}
  177. */
  178. function mergeConfigs(a, b) {
  179. /** @type {{plugins: StylelintConfigPlugins}} */
  180. const pluginMerger = {};
  181. if (a.plugins || b.plugins) {
  182. pluginMerger.plugins = [];
  183. if (a.plugins) {
  184. pluginMerger.plugins = pluginMerger.plugins.concat(a.plugins);
  185. }
  186. if (b.plugins) {
  187. pluginMerger.plugins = [...new Set(pluginMerger.plugins.concat(b.plugins))];
  188. }
  189. }
  190. /** @type {{processors: StylelintConfigProcessors}} */
  191. const processorMerger = {};
  192. if (a.processors || b.processors) {
  193. processorMerger.processors = [];
  194. if (a.processors) {
  195. processorMerger.processors = processorMerger.processors.concat(a.processors);
  196. }
  197. if (b.processors) {
  198. processorMerger.processors = [...new Set(processorMerger.processors.concat(b.processors))];
  199. }
  200. }
  201. const rulesMerger = {};
  202. if (a.rules || b.rules) {
  203. rulesMerger.rules = { ...a.rules, ...b.rules };
  204. }
  205. const result = { ...a, ...b, ...processorMerger, ...pluginMerger, ...rulesMerger };
  206. return result;
  207. }
  208. /**
  209. * @param {StylelintConfig} config
  210. * @returns {StylelintConfig}
  211. */
  212. function addPluginFunctions(config) {
  213. if (!config.plugins) return config;
  214. const normalizedPlugins = Array.isArray(config.plugins) ? config.plugins : [config.plugins];
  215. const pluginFunctions = normalizedPlugins.reduce((result, pluginLookup) => {
  216. let pluginImport = require(pluginLookup);
  217. // Handle either ES6 or CommonJS modules
  218. pluginImport = pluginImport.default || pluginImport;
  219. // A plugin can export either a single rule definition
  220. // or an array of them
  221. const normalizedPluginImport = Array.isArray(pluginImport) ? pluginImport : [pluginImport];
  222. normalizedPluginImport.forEach((pluginRuleDefinition) => {
  223. if (!pluginRuleDefinition.ruleName) {
  224. throw configurationError(
  225. 'stylelint v3+ requires plugins to expose a ruleName. ' +
  226. `The plugin "${pluginLookup}" is not doing this, so will not work ` +
  227. 'with stylelint v3+. Please file an issue with the plugin.',
  228. );
  229. }
  230. if (!pluginRuleDefinition.ruleName.includes('/')) {
  231. throw configurationError(
  232. 'stylelint v7+ requires plugin rules to be namespaced, ' +
  233. 'i.e. only `plugin-namespace/plugin-rule-name` plugin rule names are supported. ' +
  234. `The plugin rule "${pluginRuleDefinition.ruleName}" does not do this, so will not work. ` +
  235. 'Please file an issue with the plugin.',
  236. );
  237. }
  238. result[pluginRuleDefinition.ruleName] = pluginRuleDefinition.rule;
  239. });
  240. return result;
  241. }, /** @type {{[k: string]: Function}} */ ({}));
  242. config.pluginFunctions = pluginFunctions;
  243. return config;
  244. }
  245. /**
  246. * Given an array of processors strings, we want to add two
  247. * properties to the augmented config:
  248. * - codeProcessors: functions that will run on code as it comes in
  249. * - resultProcessors: functions that will run on results as they go out
  250. *
  251. * To create these properties, we need to:
  252. * - Find the processor module
  253. * - Initialize the processor module by calling its functions with any
  254. * provided options
  255. * - Push the processor's code and result processors to their respective arrays
  256. * @type {Map<string, string | Object>}
  257. */
  258. const processorCache = new Map();
  259. /**
  260. * @param {StylelintConfig} config
  261. * @return {StylelintConfig}
  262. */
  263. function addProcessorFunctions(config) {
  264. if (!config.processors) return config;
  265. /** @type {Array<Function>} */
  266. const codeProcessors = [];
  267. /** @type {Array<Function>} */
  268. const resultProcessors = [];
  269. /** @type {Array<StylelintConfigProcessor>} */ ([])
  270. .concat(config.processors)
  271. .forEach((processorConfig) => {
  272. const processorKey = JSON.stringify(processorConfig);
  273. let initializedProcessor;
  274. if (processorCache.has(processorKey)) {
  275. initializedProcessor = processorCache.get(processorKey);
  276. } else {
  277. const processorLookup =
  278. typeof processorConfig === 'string' ? processorConfig : processorConfig[0];
  279. const processorOptions =
  280. typeof processorConfig === 'string' ? undefined : processorConfig[1];
  281. let processor = require(processorLookup);
  282. processor = processor.default || processor;
  283. initializedProcessor = processor(processorOptions);
  284. processorCache.set(processorKey, initializedProcessor);
  285. }
  286. if (initializedProcessor && initializedProcessor.code) {
  287. codeProcessors.push(initializedProcessor.code);
  288. }
  289. if (initializedProcessor && initializedProcessor.result) {
  290. resultProcessors.push(initializedProcessor.result);
  291. }
  292. });
  293. config.codeProcessors = codeProcessors;
  294. config.resultProcessors = resultProcessors;
  295. return config;
  296. }
  297. module.exports = { augmentConfigExtended, augmentConfigFull };