Skip to content

Commit

Permalink
Make stylelint disables prefix configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Fitzpatrick committed Mar 14, 2023
1 parent c9ad356 commit 448b3e0
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/wet-yaks-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": minor
---

Make stylelintCommandPrefix configurable
12 changes: 12 additions & 0 deletions docs/user-guide/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,18 @@ For example:

[More info](options.md#ignoredisables).

### `disablesPrefix`

You can set the `disablesPrefix` to change the prefix of stylelint commands used in `stylelint-disable` comments. This can be useful if you expect to have multiple instances of stylelint with different configurations running.

For example, to have stylelint disable rules with `/* stylelint-special-rules-disable */` instead of the default `/* stylelint-disable */`:

```json
{
"disablesPrefix": "stylelint-special-rules-"
}
```

## `ignoreFiles`

You can provide a glob or array of globs to ignore specific files.
Expand Down
50 changes: 50 additions & 0 deletions lib/__tests__/needlessDisables.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,56 @@ it('needlessDisables severity', async () => {
]);
});

it('needlessDisables with disablesPrefix', async () => {
const config = {
rules: { 'block-no-empty': true },
disablesPrefix: 'stylelint-special-rules-',
};

const css = stripIndent`
/* stylelint-special-rules-disable */
a {}
/* stylelint-special-rules-enable */
a {
b {} /* stylelint-special-rules-disable-line block-no-empty */
}
/* stylelint-special-rules-disable */
a { color: pink; }
/* stylelint-special-rules-enable */
a {
b { color: pink; } /* stylelint-special-rules-disable-line block-no-empty */
}
`;

const { results } = await standalone({
config,
code: css,
reportNeedlessDisables: true,
});

expect(results).toHaveLength(1);
expect(results[0].warnings).toEqual([
{
line: 7,
column: 1,
endLine: 7,
endColumn: 37,
text: 'Needless disable for "all"',
rule: '--report-needless-disables',
severity: 'error',
},
{
line: 11,
column: 21,
endLine: 11,
endColumn: 77,
text: 'Needless disable for "block-no-empty"',
rule: '--report-needless-disables',
severity: 'error',
},
]);
});

function needlessDisables(warnings) {
return warnings.filter((warning) => warning.rule === '--report-needless-disables');
}
14 changes: 9 additions & 5 deletions lib/assignDisabledRanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {
DISABLE_NEXT_LINE_COMMAND,
ENABLE_COMMAND,
extractStylelintCommand,
getStylelintCommand,
isStylelintCommand,
} = require('./utils/stylelintCommand');
const { assert, assertNumber, assertString } = require('./utils/validateTypes');
Expand Down Expand Up @@ -70,6 +71,8 @@ module.exports = function assignDisabledRanges(root, result) {
/** @type {PostcssComment?} */
let inlineEnd;

const disablesPrefix = result.stylelint.config?.disablesPrefix;

root.walkComments((comment) => {
if (inlineEnd) {
// Ignore comments already processed by grouping with a previous one.
Expand All @@ -84,7 +87,7 @@ module.exports = function assignDisabledRanges(root, result) {
if (
!(
!isStandardSyntaxComment(comment) &&
isStylelintCommand(comment) &&
isStylelintCommand(comment, disablesPrefix) &&
nextComment &&
nextComment.type === 'comment' &&
(comment.text.includes('--') || nextComment.text.startsWith('--'))
Expand All @@ -100,7 +103,7 @@ module.exports = function assignDisabledRanges(root, result) {

let current = nextComment;

while (!isStandardSyntaxComment(current) && !isStylelintCommand(current)) {
while (!isStandardSyntaxComment(current) && !isStylelintCommand(current, disablesPrefix)) {
const currentLine = (current.source && current.source.end && current.source.end.line) || 0;

if (lastLine + 1 !== currentLine) break;
Expand Down Expand Up @@ -287,11 +290,11 @@ module.exports = function assignDisabledRanges(root, result) {
function checkComment(comment) {
// Ignore comments that are not relevant commands

if (!isStylelintCommand(comment)) {
if (!isStylelintCommand(comment, disablesPrefix)) {
return;
}

switch (extractStylelintCommand(comment)) {
switch (extractStylelintCommand(comment, disablesPrefix)) {
case DISABLE_LINE_COMMAND:
processDisableLineCommand(comment);
break;
Expand All @@ -314,7 +317,8 @@ module.exports = function assignDisabledRanges(root, result) {
*/
function getCommandRules(command, fullText) {
// Allow for description (f.e. /* stylelint-disable a, b -- Description */).
const splitted = fullText.slice(command.length).split(/\s-{2,}\s/u)[0];
const fullCommand = getStylelintCommand(command, disablesPrefix);
const splitted = fullText.slice(fullCommand.length).split(/\s-{2,}\s/u)[0];

assertString(splitted);
const rules = splitted
Expand Down
2 changes: 2 additions & 0 deletions lib/lintPostcssResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const getOsEol = require('./utils/getOsEol');
const reportUnknownRuleNames = require('./reportUnknownRuleNames');
const rules = require('./rules');
const getStylelintRule = require('./utils/getStylelintRule');
const { DEFAULT_COMMAND_PREFIX } = require('./utils/stylelintCommand');

/** @typedef {import('stylelint').LinterOptions} LinterOptions */
/** @typedef {import('stylelint').PostcssResult} PostcssResult */
Expand Down Expand Up @@ -104,6 +105,7 @@ module.exports = function lintPostcssResult(stylelintOptions, postcssResult, con
Promise.all(
postcssRoots.map((postcssRoot) =>
ruleFunction(primaryOption, secondaryOptions, {
disablesPrefix: config.disablesPrefix || DEFAULT_COMMAND_PREFIX,
fix:
!disableFix &&
stylelintOptions.fix &&
Expand Down
4 changes: 2 additions & 2 deletions lib/rules/block-no-empty/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const meta = {
};

/** @type {import('stylelint').Rule} */
const rule = (primary, secondaryOptions) => {
const rule = (primary, secondaryOptions, context) => {
return (root, result) => {
const validOptions = validateOptions(
result,
Expand Down Expand Up @@ -88,7 +88,7 @@ const rule = (primary, secondaryOptions) => {
if (isComment(child)) {
if (ignoreComments) return false;

if (isStylelintCommand(child)) return false;
if (isStylelintCommand(child, context.disablesPrefix)) return false;
}

return true;
Expand Down
5 changes: 2 additions & 3 deletions lib/rules/comment-empty-line-before/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const removeEmptyLinesBefore = require('../../utils/removeEmptyLinesBefore');
const report = require('../../utils/report');
const ruleMessages = require('../../utils/ruleMessages');
const validateOptions = require('../../utils/validateOptions');
const { DEFAULT_COMMAND_PREFIX } = require('../../utils/stylelintCommand');
const { isRegExp, isString } = require('../../utils/validateTypes');

const ruleName = 'comment-empty-line-before';
Expand All @@ -26,8 +27,6 @@ const meta = {
fixable: true,
};

const stylelintCommandPrefix = 'stylelint-';

/** @type {import('stylelint').Rule} */
const rule = (primary, secondaryOptions, context) => {
return (root, result) => {
Expand Down Expand Up @@ -61,7 +60,7 @@ const rule = (primary, secondaryOptions, context) => {

// Optionally ignore stylelint commands
if (
comment.text.startsWith(stylelintCommandPrefix) &&
comment.text.startsWith(context.disablesPrefix || DEFAULT_COMMAND_PREFIX) &&
optionsMatches(secondaryOptions, 'ignore', 'stylelint-commands')
) {
return;
Expand Down
16 changes: 12 additions & 4 deletions lib/utils/__tests__/stylelintCommand.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ const postcss = require('postcss');
const { extractStylelintCommand, isStylelintCommand } = require('../stylelintCommand');

test('extractStylelintCommand', () => {
expect(extractStylelintCommand(comment('stylelint-disable'))).toBe('stylelint-disable');
expect(extractStylelintCommand(comment('stylelint-disable '))).toBe('stylelint-disable');
expect(extractStylelintCommand(comment('stylelint-disable\t'))).toBe('stylelint-disable');
expect(extractStylelintCommand(comment('stylelint-disable --'))).toBe('stylelint-disable');
expect(extractStylelintCommand(comment('stylelint-disable'))).toBe('disable');
expect(extractStylelintCommand(comment('stylelint-disable '))).toBe('disable');
expect(extractStylelintCommand(comment('stylelint-disable\t'))).toBe('disable');
expect(extractStylelintCommand(comment('stylelint-disable --'))).toBe('disable');

expect(extractStylelintCommand(comment(''))).toBe('');
expect(extractStylelintCommand(comment(' '))).toBe('');
expect(extractStylelintCommand(comment('\t'))).toBe('');

expect(extractStylelintCommand(comment('stylelint-disable'), 'stylelint-2-')).toBe(
'stylelint-disable',
);
expect(extractStylelintCommand(comment('stylelint-2-disable'), 'stylelint-2-')).toBe('disable');
});

test('isStylelintCommand', () => {
Expand All @@ -29,6 +34,9 @@ test('isStylelintCommand', () => {
expect(isStylelintCommand(comment(''))).toBe(false);
expect(isStylelintCommand(comment(' '))).toBe(false);
expect(isStylelintCommand(comment('\t'))).toBe(false);

expect(isStylelintCommand(comment('stylelint-disable'), 'stylelint-2-')).toBe(false);
expect(isStylelintCommand(comment('stylelint-2-disable'), 'stylelint-2-')).toBe(true);
});

function comment(text) {
Expand Down
33 changes: 25 additions & 8 deletions lib/utils/stylelintCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

const { assertString } = require('./validateTypes');

const DISABLE_COMMAND = 'stylelint-disable';
const DISABLE_LINE_COMMAND = 'stylelint-disable-line';
const DISABLE_NEXT_LINE_COMMAND = 'stylelint-disable-next-line';
const ENABLE_COMMAND = 'stylelint-enable';
const DISABLE_COMMAND = 'disable';
const DISABLE_LINE_COMMAND = 'disable-line';
const DISABLE_NEXT_LINE_COMMAND = 'disable-next-line';
const ENABLE_COMMAND = 'enable';

const ALL_COMMANDS = new Set([
DISABLE_COMMAND,
Expand All @@ -14,40 +14,57 @@ const ALL_COMMANDS = new Set([
ENABLE_COMMAND,
]);

const DEFAULT_COMMAND_PREFIX = 'stylelint-';

/** @typedef {import('postcss').Comment} Comment */

/**
* Extract a command from a given comment.
*
* @param {Comment} comment
* @param {string} [disablesPrefix]
* @returns {string}
*/
function extractStylelintCommand(comment) {
function extractStylelintCommand(comment, disablesPrefix = DEFAULT_COMMAND_PREFIX) {
const [command] = comment.text.split(/\s/, 1);

assertString(command);

return command;
return command.replace(disablesPrefix, '');
}

/**
* Tests if the given comment is a Stylelint command.
*
* @param {Comment} comment
* @param {string} [disablesPrefix]
* @returns {boolean}
*/
function isStylelintCommand(comment) {
const command = extractStylelintCommand(comment);
function isStylelintCommand(comment, disablesPrefix = DEFAULT_COMMAND_PREFIX) {
const command = extractStylelintCommand(comment, disablesPrefix);

return command !== undefined && ALL_COMMANDS.has(command);
}

/**
* Get full stylelint command
*
* @param {string} command
* @param {string} [disablesPrefix]
* @returns {string}
*/
function getStylelintCommand(command, disablesPrefix = DEFAULT_COMMAND_PREFIX) {
return `${disablesPrefix}${command}`;
}

module.exports = {
DEFAULT_COMMAND_PREFIX,
DISABLE_COMMAND,
DISABLE_LINE_COMMAND,
DISABLE_NEXT_LINE_COMMAND,
ENABLE_COMMAND,

extractStylelintCommand,
getStylelintCommand,
isStylelintCommand,
};
2 changes: 2 additions & 0 deletions types/stylelint/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ declare module 'stylelint' {
reportNeedlessDisables?: DisableSettings;
reportInvalidScopeDisables?: DisableSettings;
reportDescriptionlessDisables?: DisableSettings;
disablesPrefix?: string;
overrides?: ConfigOverride[];
customSyntax?: CustomSyntax;
};
Expand Down Expand Up @@ -190,6 +191,7 @@ declare module 'stylelint' {
* A rule context.
*/
export type RuleContext = {
disablesPrefix?: string | undefined;
fix?: boolean | undefined;
newline?: string | undefined;
};
Expand Down

0 comments on commit 448b3e0

Please sign in to comment.