Skip to content

Commit

Permalink
Create new 'lintPostcssResult' module (#4819)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-allanson committed Jun 9, 2020
1 parent 0f69eac commit 8e07ca0
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 137 deletions.
142 changes: 142 additions & 0 deletions lib/lintPostcssResult.js
@@ -0,0 +1,142 @@
'use strict';

const assignDisabledRanges = require('./assignDisabledRanges');
const get = require('lodash/get');
const getOsEol = require('./utils/getOsEol');
const reportUnknownRuleNames = require('./reportUnknownRuleNames');
const rulesOrder = require('./rules');

/** @typedef {import('stylelint').StylelintStandaloneOptions} StylelintStandaloneOptions */
/** @typedef {import('stylelint').PostcssResult} PostcssResult */
/** @typedef {import('stylelint').StylelintConfig} StylelintConfig */

/**
* @param {StylelintStandaloneOptions} stylelintOptions
* @param {PostcssResult} postcssResult
* @param {StylelintConfig} config
* @returns {Promise<any>}
*/
function lintPostcssResult(stylelintOptions, postcssResult, config) {
postcssResult.stylelint.ruleSeverities = {};
postcssResult.stylelint.customMessages = {};
postcssResult.stylelint.stylelintError = false;
postcssResult.stylelint.quiet = config.quiet;
postcssResult.stylelint.config = config;

/** @type {string} */
let newline;
const postcssDoc = postcssResult.root;

if (postcssDoc) {
if (!('type' in postcssDoc)) {
throw new Error('Unexpected Postcss root object!');
}

// @ts-ignore TODO TYPES property css does not exists
const newlineMatch = postcssDoc.source && postcssDoc.source.input.css.match(/\r?\n/);

newline = newlineMatch ? newlineMatch[0] : getOsEol();

assignDisabledRanges(postcssDoc, postcssResult);
}

if (stylelintOptions.ignoreDisables) {
postcssResult.stylelint.ignoreDisables = true;
}

if (stylelintOptions.reportNeedlessDisables) {
postcssResult.stylelint.reportNeedlessDisables = true;
}

const isFileFixCompatible = isFixCompatible(postcssResult);

if (!isFileFixCompatible) {
postcssResult.stylelint.disableWritingFix = true;
}

const postcssRoots = /** @type {import('postcss').Root[]} */ (postcssDoc &&
postcssDoc.constructor.name === 'Document'
? postcssDoc.nodes
: [postcssDoc]);

// Promises for the rules. Although the rule code runs synchronously now,
// the use of Promises makes it compatible with the possibility of async
// rules down the line.
/** @type {Array<Promise<any>>} */
const performRules = [];

const rules = config.rules
? Object.keys(config.rules).sort(
(a, b) => Object.keys(rulesOrder).indexOf(a) - Object.keys(rulesOrder).indexOf(b),
)
: [];

rules.forEach((ruleName) => {
const ruleFunction = rulesOrder[ruleName] || get(config, ['pluginFunctions', ruleName]);

if (ruleFunction === undefined) {
performRules.push(
Promise.all(
postcssRoots.map((postcssRoot) =>
reportUnknownRuleNames(ruleName, postcssRoot, postcssResult),
),
),
);

return;
}

const ruleSettings = get(config, ['rules', ruleName]);

if (ruleSettings === null || ruleSettings[0] === null) {
return;
}

const primaryOption = ruleSettings[0];
const secondaryOptions = ruleSettings[1];

// Log the rule's severity in the PostCSS result
const defaultSeverity = config.defaultSeverity || 'error';

postcssResult.stylelint.ruleSeverities[ruleName] = get(
secondaryOptions,
'severity',
defaultSeverity,
);
postcssResult.stylelint.customMessages[ruleName] = get(secondaryOptions, 'message');

performRules.push(
Promise.all(
postcssRoots.map((postcssRoot) =>
ruleFunction(primaryOption, secondaryOptions, {
fix:
stylelintOptions.fix &&
// Next two conditionals are temporary measures until #2643 is resolved
isFileFixCompatible &&
!postcssResult.stylelint.disabledRanges[ruleName],
newline,
})(postcssRoot, postcssResult),
),
),
);
});

return Promise.all(performRules);
}

/**
* There are currently some bugs in the autofixer of Stylelint.
* The autofixer does not yet adhere to stylelint-disable comments, so if there are disabled
* ranges we can not autofix this document. More info in issue #2643.
*
* @param {PostcssResult} postcssResult
* @returns {boolean}
*/
function isFixCompatible({ stylelint }) {
// Check for issue #2643
if (stylelint.disabledRanges.all.length) return false;

return true;
}

module.exports = lintPostcssResult;
142 changes: 5 additions & 137 deletions lib/lintSource.js
@@ -1,16 +1,13 @@
'use strict';

const _ = require('lodash');
const assignDisabledRanges = require('./assignDisabledRanges');
const getOsEol = require('./utils/getOsEol');
const lintPostcssResult = require('./lintPostcssResult');
const path = require('path');
const reportUnknownRuleNames = require('./reportUnknownRuleNames');
const rulesOrder = require('./rules');

/** @typedef {import('stylelint').StylelintInternalApi} StylelintInternalApi */
/** @typedef {import('stylelint').GetLintSourceOptions} Options */
/** @typedef {import('postcss').Result} Result */
/** @typedef {import('stylelint').PostcssResult} PostcssResult */
/** @typedef {import('stylelint').StylelintPostcssResult} StylelintPostcssResult */
/** @typedef {import('stylelint').GetLintSourceOptions} Options */

/**
* Run stylelint on a PostCSS Result, either one that is provided
Expand Down Expand Up @@ -84,7 +81,7 @@ module.exports = function lintSource(stylelint, options = {}) {
stylelint: stylelintResult,
});

return lintPostcssResult(stylelint, stylelintPostcssResult, config).then(
return lintPostcssResult(stylelint._options, stylelintPostcssResult, config).then(
() => stylelintPostcssResult,
);
}
Expand All @@ -101,128 +98,14 @@ module.exports = function lintSource(stylelint, options = {}) {
stylelint: stylelintResult,
});

return lintPostcssResult(stylelint, stylelintPostcssResult, config).then(
return lintPostcssResult(stylelint._options, stylelintPostcssResult, config).then(
() => stylelintPostcssResult,
);
});
});
});
};

/**
* @param {StylelintInternalApi} stylelint
* @param {PostcssResult} postcssResult
* @param {import('stylelint').StylelintConfig} config
* @returns {Promise<any>}
*/
function lintPostcssResult(stylelint, postcssResult, config) {
postcssResult.stylelint.ruleSeverities = {};
postcssResult.stylelint.customMessages = {};
postcssResult.stylelint.stylelintError = false;
postcssResult.stylelint.quiet = config.quiet;
postcssResult.stylelint.config = config;

/** @type {string} */
let newline;
const postcssDoc = postcssResult.root;

if (postcssDoc) {
if (!('type' in postcssDoc)) {
throw new Error('Unexpected Postcss root object!');
}

// @ts-ignore TODO TYPES property css does not exists
const newlineMatch = postcssDoc.source && postcssDoc.source.input.css.match(/\r?\n/);

newline = newlineMatch ? newlineMatch[0] : getOsEol();

assignDisabledRanges(postcssDoc, postcssResult);
}

if (stylelint._options.ignoreDisables) {
postcssResult.stylelint.ignoreDisables = true;
}

if (stylelint._options.reportNeedlessDisables) {
postcssResult.stylelint.reportNeedlessDisables = true;
}

const isFileFixCompatible = isFixCompatible(postcssResult);

if (!isFileFixCompatible) {
postcssResult.stylelint.disableWritingFix = true;
}

const postcssRoots = /** @type {import('postcss').Root[]} */ (postcssDoc &&
postcssDoc.constructor.name === 'Document'
? postcssDoc.nodes
: [postcssDoc]);

// Promises for the rules. Although the rule code runs synchronously now,
// the use of Promises makes it compatible with the possibility of async
// rules down the line.
/** @type {Array<Promise<any>>} */
const performRules = [];

const rules = config.rules
? Object.keys(config.rules).sort(
(a, b) => Object.keys(rulesOrder).indexOf(a) - Object.keys(rulesOrder).indexOf(b),
)
: [];

rules.forEach((ruleName) => {
const ruleFunction = rulesOrder[ruleName] || _.get(config, ['pluginFunctions', ruleName]);

if (ruleFunction === undefined) {
performRules.push(
Promise.all(
postcssRoots.map((postcssRoot) =>
reportUnknownRuleNames(ruleName, postcssRoot, postcssResult),
),
),
);

return;
}

const ruleSettings = _.get(config, ['rules', ruleName]);

if (ruleSettings === null || ruleSettings[0] === null) {
return;
}

const primaryOption = ruleSettings[0];
const secondaryOptions = ruleSettings[1];

// Log the rule's severity in the PostCSS result
const defaultSeverity = config.defaultSeverity || 'error';

postcssResult.stylelint.ruleSeverities[ruleName] = _.get(
secondaryOptions,
'severity',
defaultSeverity,
);
postcssResult.stylelint.customMessages[ruleName] = _.get(secondaryOptions, 'message');

performRules.push(
Promise.all(
postcssRoots.map((postcssRoot) =>
ruleFunction(primaryOption, secondaryOptions, {
fix:
stylelint._options.fix &&
// Next two conditionals are temporary measures until #2643 is resolved
isFileFixCompatible &&
!postcssResult.stylelint.disabledRanges[ruleName],
newline,
})(postcssRoot, postcssResult),
),
),
);
});

return Promise.all(performRules);
}

/**
* @returns {StylelintPostcssResult}
*/
Expand Down Expand Up @@ -253,18 +136,3 @@ function createEmptyPostcssResult(filePath) {
warn: () => {},
};
}

/**
* There are currently some bugs in the autofixer of Stylelint.
* The autofixer does not yet adhere to stylelint-disable comments, so if there are disabled
* ranges we can not autofix this document. More info in issue #2643.
*
* @param {PostcssResult} postcssResult
* @returns {boolean}
*/
function isFixCompatible({ stylelint }) {
// Check for issue #2643
if (stylelint.disabledRanges.all.length) return false;

return true;
}

0 comments on commit 8e07ca0

Please sign in to comment.