Skip to content

Commit

Permalink
Refactor to improve types for selector-attribute-* rules (#5836)
Browse files Browse the repository at this point in the history
  • Loading branch information
ybiquitous committed Jan 17, 2022
1 parent 7af4b10 commit 9e75552
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 86 deletions.
72 changes: 41 additions & 31 deletions lib/rules/selector-attribute-brackets-space-inside/index.js
@@ -1,5 +1,3 @@
// @ts-nocheck

'use strict';

const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
Expand All @@ -18,10 +16,11 @@ const messages = ruleMessages(ruleName, {
rejectedClosing: 'Unexpected whitespace before "]"',
});

function rule(expectation, options, context) {
/** @type {import('stylelint').Rule} */
const rule = (primary, _secondaryOptions, context) => {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
actual: primary,
possible: ['always', 'never'],
});

Expand Down Expand Up @@ -49,7 +48,7 @@ function rule(expectation, options, context) {
const nextCharIsSpace = attributeSelectorString[match.startIndex + 1] === ' ';
const index = attributeNode.sourceIndex + match.startIndex + 1;

if (nextCharIsSpace && expectation === 'never') {
if (nextCharIsSpace && primary === 'never') {
if (context.fix) {
hasFixed = true;
fixBefore(attributeNode);
Expand All @@ -60,7 +59,7 @@ function rule(expectation, options, context) {
complain(messages.rejectedOpening, index);
}

if (!nextCharIsSpace && expectation === 'always') {
if (!nextCharIsSpace && primary === 'always') {
if (context.fix) {
hasFixed = true;
fixBefore(attributeNode);
Expand All @@ -76,7 +75,7 @@ function rule(expectation, options, context) {
const prevCharIsSpace = attributeSelectorString[match.startIndex - 1] === ' ';
const index = attributeNode.sourceIndex + match.startIndex - 1;

if (prevCharIsSpace && expectation === 'never') {
if (prevCharIsSpace && primary === 'never') {
if (context.fix) {
hasFixed = true;
fixAfter(attributeNode);
Expand All @@ -87,7 +86,7 @@ function rule(expectation, options, context) {
complain(messages.rejectedClosing, index);
}

if (!prevCharIsSpace && expectation === 'always') {
if (!prevCharIsSpace && primary === 'always') {
if (context.fix) {
hasFixed = true;
fixAfter(attributeNode);
Expand All @@ -101,14 +100,18 @@ function rule(expectation, options, context) {
});
});

if (hasFixed) {
if (hasFixed && fixedSelector) {
if (!ruleNode.raws.selector) {
ruleNode.selector = fixedSelector;
} else {
ruleNode.raws.selector.raw = fixedSelector;
}
}

/**
* @param {string} message
* @param {number} index
*/
function complain(message, index) {
report({
message,
Expand All @@ -121,16 +124,19 @@ function rule(expectation, options, context) {
});
};

/**
* @param {import('postcss-selector-parser').Attribute} attributeNode
*/
function fixBefore(attributeNode) {
const rawAttrBefore =
attributeNode.raws.spaces &&
attributeNode.raws.spaces.attribute &&
attributeNode.raws.spaces.attribute.before;
const spacesAttribute = attributeNode.raws.spaces && attributeNode.raws.spaces.attribute;
const rawAttrBefore = spacesAttribute && spacesAttribute.before;

/** @type {{ attrBefore: string, setAttrBefore: (fixed: string) => void }} */
const { attrBefore, setAttrBefore } = rawAttrBefore
? {
attrBefore: rawAttrBefore,
setAttrBefore(fixed) {
attributeNode.raws.spaces.attribute.before = fixed;
spacesAttribute.before = fixed;
},
}
: {
Expand All @@ -143,49 +149,53 @@ function rule(expectation, options, context) {
},
};

if (expectation === 'always') {
if (primary === 'always') {
setAttrBefore(attrBefore.replace(/^\s*/, ' '));
} else if (expectation === 'never') {
} else if (primary === 'never') {
setAttrBefore(attrBefore.replace(/^\s*/, ''));
}
}

/**
* @param {import('postcss-selector-parser').Attribute} attributeNode
*/
function fixAfter(attributeNode) {
let key;
const key = attributeNode.operator
? attributeNode.insensitive
? 'insensitive'
: 'value'
: 'attribute';

if (attributeNode.operator) {
key = attributeNode.insensitive ? 'insensitive' : 'value';
} else {
key = 'attribute';
}
const rawSpaces = attributeNode.raws.spaces && attributeNode.raws.spaces[key];
const rawAfter = rawSpaces && rawSpaces.after;

const spaces = attributeNode.spaces[key];

const rawAfter =
attributeNode.raws.spaces &&
attributeNode.raws.spaces[key] &&
attributeNode.raws.spaces[key].after;
/** @type {{ after: string, setAfter: (fixed: string) => void }} */
const { after, setAfter } = rawAfter
? {
after: rawAfter,
setAfter(fixed) {
attributeNode.raws.spaces[key].after = fixed;
rawSpaces.after = fixed;
},
}
: {
after: (attributeNode.spaces[key] && attributeNode.spaces[key].after) || '',
after: (spaces && spaces.after) || '',
setAfter(fixed) {
if (!attributeNode.spaces[key]) attributeNode.spaces[key] = {};

// @ts-expect-error -- TS2532: Object is possibly 'undefined'.
attributeNode.spaces[key].after = fixed;
},
};

if (expectation === 'always') {
if (primary === 'always') {
setAfter(after.replace(/\s*$/, ' '));
} else if (expectation === 'never') {
} else if (primary === 'never') {
setAfter(after.replace(/\s*$/, ''));
}
}
}
};

rule.ruleName = ruleName;
rule.messages = messages;
Expand Down
9 changes: 4 additions & 5 deletions lib/rules/selector-attribute-name-disallowed-list/index.js
@@ -1,5 +1,3 @@
// @ts-nocheck

'use strict';

const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
Expand All @@ -16,8 +14,9 @@ const messages = ruleMessages(ruleName, {
rejected: (name) => `Unexpected name "${name}"`,
});

function rule(listInput) {
const list = [listInput].flat();
/** @type {import('stylelint').Rule} */
const rule = (primary) => {
const list = [primary].flat();

return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
Expand Down Expand Up @@ -57,7 +56,7 @@ function rule(listInput) {
});
});
};
}
};

rule.primaryOptionArray = true;

Expand Down
9 changes: 4 additions & 5 deletions lib/rules/selector-attribute-operator-allowed-list/index.js
@@ -1,5 +1,3 @@
// @ts-nocheck

'use strict';

const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
Expand All @@ -15,8 +13,9 @@ const messages = ruleMessages(ruleName, {
rejected: (operator) => `Unexpected operator "${operator}"`,
});

function rule(listInput) {
const list = [listInput].flat();
/** @type {import('stylelint').Rule} */
const rule = (primary) => {
const list = [primary].flat();

return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
Expand Down Expand Up @@ -56,7 +55,7 @@ function rule(listInput) {
});
});
};
}
};

rule.primaryOptionArray = true;

Expand Down
@@ -1,5 +1,3 @@
// @ts-nocheck

'use strict';

const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
Expand All @@ -15,8 +13,9 @@ const messages = ruleMessages(ruleName, {
rejected: (operator) => `Unexpected operator "${operator}"`,
});

function rule(listInput) {
const list = [listInput].flat();
/** @type {import('stylelint').Rule} */
const rule = (primary) => {
const list = [primary].flat();

return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
Expand Down Expand Up @@ -56,7 +55,7 @@ function rule(listInput) {
});
});
};
}
};

rule.primaryOptionArray = true;

Expand Down
31 changes: 17 additions & 14 deletions lib/rules/selector-attribute-operator-space-after/index.js
@@ -1,5 +1,3 @@
// @ts-nocheck

'use strict';

const ruleMessages = require('../../utils/ruleMessages');
Expand All @@ -14,11 +12,12 @@ const messages = ruleMessages(ruleName, {
rejectedAfter: (operator) => `Unexpected whitespace after "${operator}"`,
});

function rule(expectation, options, context) {
/** @type {import('stylelint').Rule} */
const rule = (primary, _secondaryOptions, context) => {
return (root, result) => {
const checker = whitespaceChecker('space', expectation, messages);
const checker = whitespaceChecker('space', primary, messages);
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
actual: primary,
possible: ['always', 'never'],
});

Expand All @@ -34,12 +33,15 @@ function rule(expectation, options, context) {
checkBeforeOperator: false,
fix: context.fix
? (attributeNode) => {
/** @type {{ operatorAfter: string, setOperatorAfter: (fixed: string) => void }} */
const { operatorAfter, setOperatorAfter } = (() => {
const rawOperator = attributeNode.raws.operator;

if (rawOperator) {
return {
operatorAfter: rawOperator.slice(attributeNode.operator.length),
operatorAfter: rawOperator.slice(
attributeNode.operator ? attributeNode.operator.length : 0,
),
setOperatorAfter(fixed) {
delete attributeNode.raws.operator;

Expand All @@ -53,16 +55,15 @@ function rule(expectation, options, context) {
};
}

const rawOperatorAfter =
attributeNode.raws.spaces &&
attributeNode.raws.spaces.operator &&
attributeNode.raws.spaces.operator.after;
const rawSpacesOperator =
attributeNode.raws.spaces && attributeNode.raws.spaces.operator;
const rawOperatorAfter = rawSpacesOperator && rawSpacesOperator.after;

if (rawOperatorAfter) {
return {
operatorAfter: rawOperatorAfter,
setOperatorAfter(fixed) {
attributeNode.raws.spaces.operator.after = fixed;
rawSpacesOperator.after = fixed;
},
};
}
Expand All @@ -78,22 +79,24 @@ function rule(expectation, options, context) {
};
})();

if (expectation === 'always') {
if (primary === 'always') {
setOperatorAfter(operatorAfter.replace(/^\s*/, ' '));

return true;
}

if (expectation === 'never') {
if (primary === 'never') {
setOperatorAfter(operatorAfter.replace(/^\s*/, ''));

return true;
}

return false;
}
: null,
});
};
}
};

rule.ruleName = ruleName;
rule.messages = messages;
Expand Down

0 comments on commit 9e75552

Please sign in to comment.