lintPostcssResult.cjs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // NOTICE: This file is generated by Rollup. To modify it,
  2. // please instead edit the ESM counterpart and rebuild with Rollup (npm run build).
  3. 'use strict';
  4. const node_os = require('node:os');
  5. const constants = require('./constants.cjs');
  6. const configurationComment = require('./utils/configurationComment.cjs');
  7. const assignDisabledRanges = require('./assignDisabledRanges.cjs');
  8. const emitWarning = require('./utils/emitWarning.cjs');
  9. const cssTree = require('css-tree');
  10. const getStylelintRule = require('./utils/getStylelintRule.cjs');
  11. const reportUnknownRuleNames = require('./reportUnknownRuleNames.cjs');
  12. const index = require('./rules/index.cjs');
  13. const timing = require('./timing.cjs');
  14. /** @import {Config, LinterOptions, PostcssResult} from 'stylelint' */
  15. /**
  16. * @param {LinterOptions} stylelintOptions
  17. * @param {PostcssResult} postcssResult
  18. * @param {Config} config
  19. * @returns {Promise<any>}
  20. */
  21. async function lintPostcssResult(stylelintOptions, postcssResult, config) {
  22. postcssResult.stylelint.stylelintError = false;
  23. postcssResult.stylelint.stylelintWarning = false;
  24. postcssResult.stylelint.quiet = config.quiet;
  25. postcssResult.stylelint.quietDeprecationWarnings = stylelintOptions.quietDeprecationWarnings;
  26. postcssResult.stylelint.config = config;
  27. const postcssDoc = postcssResult.root;
  28. if (!('type' in postcssDoc)) {
  29. throw new Error('Unexpected Postcss root object!');
  30. }
  31. const newlineMatch = postcssDoc.source?.input.css.match(/\r?\n/);
  32. const newline = newlineMatch ? newlineMatch[0] : node_os.EOL;
  33. const configurationComment$1 = config.configurationComment || configurationComment.DEFAULT_CONFIGURATION_COMMENT;
  34. const ctx = { configurationComment: configurationComment$1, newline };
  35. assignDisabledRanges(postcssDoc, postcssResult);
  36. const postcssRoots = /** @type {import('postcss').Root[]} */ (
  37. postcssDoc && postcssDoc.constructor.name === 'Document' ? postcssDoc.nodes : [postcssDoc]
  38. );
  39. // Promises for the rules. Although the rule code runs synchronously now,
  40. // the use of Promises makes it compatible with the possibility of async
  41. // rules down the line.
  42. /** @type {Array<Promise<any>>} */
  43. const performRules = [];
  44. const rulesOrder = Object.keys(index);
  45. const ruleNames = config.rules
  46. ? Object.keys(config.rules).sort((a, b) => rulesOrder.indexOf(a) - rulesOrder.indexOf(b))
  47. : [];
  48. for (const ruleName of ruleNames) {
  49. const ruleFunction = await getStylelintRule(ruleName, config);
  50. if (ruleFunction === undefined) {
  51. performRules.push(
  52. Promise.all(
  53. postcssRoots.map((postcssRoot) =>
  54. reportUnknownRuleNames(ruleName, postcssRoot, postcssResult),
  55. ),
  56. ),
  57. );
  58. continue;
  59. }
  60. const ruleSettings = config.rules?.[ruleName];
  61. if (ruleSettings === null || ruleSettings[0] === null) continue;
  62. if (ruleFunction.meta?.deprecated && !stylelintOptions.quietDeprecationWarnings) {
  63. warnDeprecatedRule(postcssResult, ruleName);
  64. }
  65. const primaryOption = ruleSettings[0];
  66. const secondaryOptions = ruleSettings[1];
  67. // Log the rule's severity in the PostCSS result
  68. const defaultSeverity = config.defaultSeverity || constants.DEFAULT_SEVERITY;
  69. postcssResult.stylelint.ruleSeverities[ruleName] =
  70. (secondaryOptions && secondaryOptions.severity) || defaultSeverity;
  71. postcssResult.stylelint.customMessages[ruleName] = secondaryOptions && secondaryOptions.message;
  72. postcssResult.stylelint.customUrls[ruleName] = secondaryOptions && secondaryOptions.url;
  73. postcssResult.stylelint.ruleMetadata[ruleName] = ruleFunction.meta || {};
  74. const shouldWarn = ruleFunction.meta?.fixable && !stylelintOptions.quietDeprecationWarnings;
  75. const disableFix = secondaryOptions?.disableFix === true;
  76. const fix = !disableFix && config.fix && isFixCompatible(postcssResult, ruleName);
  77. const lexer = getCachedLexer(config);
  78. const context = {
  79. ...ctx,
  80. lexer,
  81. // context.fix is unlikely to be removed in the foreseeable future
  82. // due to the sheer number of rules in the wild that rely on it
  83. get fix() {
  84. if (shouldWarn) {
  85. emitWarning.emitDeprecationWarning(
  86. '`context.fix` is being deprecated.',
  87. 'CONTEXT_FIX',
  88. `Please pass a \`fix\` callback to the \`report\` utility of "${ruleName}" instead.`,
  89. );
  90. }
  91. return fix;
  92. },
  93. };
  94. const ruleFn = ruleFunction(primaryOption, secondaryOptions, context);
  95. /**
  96. * @param {import('postcss').Root} postcssRoot
  97. */
  98. async function runRule(postcssRoot) {
  99. if (timing.enabled) {
  100. return timing.time(ruleName, () => ruleFn(postcssRoot, postcssResult))();
  101. }
  102. return ruleFn(postcssRoot, postcssResult);
  103. }
  104. performRules.push(Promise.all(postcssRoots.map(runRule)));
  105. }
  106. return Promise.all(performRules);
  107. }
  108. /**
  109. * using context.fix instead of the fix callback has the drawback
  110. * of not honouring the configuration comments in subtle ways
  111. * @see file://./../docs/user-guide/options.md#fix for details
  112. * @param {PostcssResult} postcssResult
  113. * @param {string} name
  114. * @returns {boolean}
  115. */
  116. function isFixCompatible({ stylelint: { disabledRanges } }, name) {
  117. return !disabledRanges[constants.RULE_NAME_ALL]?.length && !disabledRanges[name];
  118. }
  119. /**
  120. * @param {PostcssResult} result
  121. * @param {string} ruleName
  122. * @returns {void}
  123. */
  124. function warnDeprecatedRule(result, ruleName) {
  125. const message = `The "${ruleName}" rule is deprecated.`;
  126. emitWarning.emitDeprecationWarning(
  127. message,
  128. 'RULE',
  129. `Please be aware that the "${ruleName}" rule will soon be either removed or renamed.`,
  130. );
  131. result.warn(message, { stylelintType: 'deprecation' });
  132. }
  133. const lexerCache = new Map();
  134. /**
  135. * @param {Config} config
  136. * @returns {import('css-tree').Lexer}
  137. * */
  138. function getCachedLexer(config) {
  139. const cacheKey = JSON.stringify(config.languageOptions?.syntax || {});
  140. if (lexerCache.has(cacheKey)) {
  141. return lexerCache.get(cacheKey);
  142. }
  143. const newLexer = cssTree.fork({
  144. atrules: config.languageOptions?.syntax?.atRules || {},
  145. properties: config.languageOptions?.syntax?.properties || {},
  146. types: config.languageOptions?.syntax?.types || {},
  147. cssWideKeywords: config.languageOptions?.syntax?.cssWideKeywords || [],
  148. }).lexer;
  149. lexerCache.set(cacheKey, newLexer);
  150. return newLexer;
  151. }
  152. module.exports = lintPostcssResult;