Skip to content

Commit

Permalink
Merge branch 'main' into fix-nvp-p
Browse files Browse the repository at this point in the history
  • Loading branch information
jeddy3 committed Jun 30, 2023
2 parents 06bcf08 + d2c398c commit df0e7e4
Show file tree
Hide file tree
Showing 22 changed files with 208 additions and 138 deletions.
5 changes: 5 additions & 0 deletions .changeset/bright-suits-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": patch
---

Fixed: `function-name-case` performance
5 changes: 5 additions & 0 deletions .changeset/empty-starfishes-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": patch
---

Fixed: `hue-degree-notation` performance
5 changes: 5 additions & 0 deletions .changeset/hot-doors-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": patch
---

Fixed: `custom-property-pattern` performance
5 changes: 5 additions & 0 deletions .changeset/silly-eagles-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": patch
---

Fixed: `selector-id-pattern` performance
5 changes: 5 additions & 0 deletions .changeset/ten-mirrors-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": patch
---

Fixed: `hue-degree-notation` false negatives for `oklch`
5 changes: 5 additions & 0 deletions .changeset/tender-apes-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": patch
---

Fixed: `function-url-quotes` performance
12 changes: 4 additions & 8 deletions docs/developer-guide/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ Deprecating rules doesn't happen very often. When you do, you must:

## Improve the performance of a rule

You can run a benchmarks on any given rule with any valid config using:
You can run a benchmark on any given rule with any valid config using:

```shell
npm run benchmark-rule -- ruleName ruleOptions [ruleContext]
Expand All @@ -296,21 +296,17 @@ npm run benchmark-rule -- ruleName ruleOptions [ruleContext]
If the `ruleOptions` argument is anything other than a string or a boolean, it must be valid JSON wrapped in quotation marks.

```shell
npm run benchmark-rule -- selector-combinator-space-after never
npm run benchmark-rule -- value-keyword-case lower
```

```shell
npm run benchmark-rule -- selector-combinator-space-after always
```

```shell
npm run benchmark-rule -- block-opening-brace-space-before "[\"always\", {\"ignoreAtRules\": [\"else\"]}]"
npm run benchmark-rule -- value-keyword-case '["lower", {"camelCaseSvgKeywords": true}]'
```

If the `ruleContext` argument is specified, the sames procedure would apply:

```shell
npm run benchmark-rule -- block-opening-brace-space-before "[\"always\", {\"ignoreAtRules\": [\"else\"]}]" "{\"fix\": \"true\"}"
npm run benchmark-rule -- value-keyword-case '["lower", {"camelCaseSvgKeywords": true}]' '{"fix": true}'
```

The script loads Bootstrap's CSS (from its CDN) and runs it through the configured rule.
Expand Down
24 changes: 14 additions & 10 deletions lib/rules/custom-property-pattern/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const meta = {
url: 'https://stylelint.io/user-guide/rules/custom-property-pattern',
};

const VAR_FUNC_REGEX = /var\(/i;

/** @type {import('stylelint').Rule} */
const rule = (primary) => {
return (root, result) => {
Expand All @@ -40,30 +42,32 @@ const rule = (primary) => {
*/
function check(property) {
return (
!isStandardSyntaxProperty(property) ||
!isCustomProperty(property) ||
!isStandardSyntaxProperty(property) ||
regexpPattern.test(property.slice(2))
);
}

root.walkDecls((decl) => {
const { prop, value } = decl;

const parsedValue = valueParser(value);
if (VAR_FUNC_REGEX.test(value)) {
const parsedValue = valueParser(value);

parsedValue.walk((node) => {
if (!isValueFunction(node)) return;
parsedValue.walk((node) => {
if (!isValueFunction(node)) return;

if (node.value.toLowerCase() !== 'var') return;
if (node.value.toLowerCase() !== 'var') return;

const { nodes } = node;
const { nodes } = node;

const firstNode = nodes[0];
const firstNode = nodes[0];

if (!firstNode || check(firstNode.value)) return;
if (!firstNode || check(firstNode.value)) return;

complain(declarationValueIndex(decl) + firstNode.sourceIndex, firstNode.value, decl);
});
complain(declarationValueIndex(decl) + firstNode.sourceIndex, firstNode.value, decl);
});
}

if (check(prop)) return;

Expand Down
2 changes: 2 additions & 0 deletions lib/rules/function-name-case/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ const rule = (primary, secondaryOptions, context) => {
}

root.walkDecls((decl) => {
if (!decl.value.includes('(')) return;

if (!isStandardSyntaxValue(decl.value)) return;

let needFix = false;
Expand Down
4 changes: 2 additions & 2 deletions lib/rules/function-no-unknown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ const rule = (primary, secondaryOptions) => {
if (isFunctionNode(componentValue) || isSimpleBlockNode(componentValue)) {
walker(componentValue);

componentValue.walk((entry) => {
walker(entry.node);
componentValue.walk(({ node }) => {
walker(node);
});
}
});
Expand Down
4 changes: 4 additions & 0 deletions lib/rules/function-url-quotes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const meta = {
fixable: true,
};

const URL_FUNC_REGEX = /url\(/i;

/** @type {import('stylelint').Rule} */
const rule = (primary, secondaryOptions, context) => {
return (root, result) => {
Expand Down Expand Up @@ -57,6 +59,8 @@ const rule = (primary, secondaryOptions, context) => {
* @param {import('postcss').Declaration} decl
*/
function checkDeclParams(decl) {
if (!URL_FUNC_REGEX.test(decl.value)) return;

if (!isStandardSyntaxDeclaration(decl)) return;

const value = getDeclarationValue(decl);
Expand Down
21 changes: 21 additions & 0 deletions lib/rules/hue-degree-notation/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ testRule({
code: 'a { color: lch(56.29% 19.86) }',
description: 'malformed lch',
},
{
code: 'a { color: oklch(56.29% 19.86 10deg) }',
},
{
code: 'a { color: hsl(170deg 60% 50% / 15%) }',
},
Expand Down Expand Up @@ -98,6 +101,15 @@ testRule({
endLine: 1,
endColumn: 31,
},
{
code: 'a { color: oklch(56.29% 19.86 10) }',
fixed: 'a { color: oklch(56.29% 19.86 10deg) }',
message: messages.expected('10', '10deg'),
line: 1,
column: 31,
endLine: 1,
endColumn: 33,
},
{
code: 'a { color: hsl(/*comment*/120 60% 70%) }',
fixed: 'a { color: hsl(/*comment*/120deg 60% 70%) }',
Expand Down Expand Up @@ -200,6 +212,15 @@ testRule({
endLine: 1,
endColumn: 34,
},
{
code: 'a { color: oklch(56.29% 19.86 10deg) }',
fixed: 'a { color: oklch(56.29% 19.86 10) }',
message: messages.expected('10deg', '10'),
line: 1,
column: 31,
endLine: 1,
endColumn: 36,
},
{
code: stripIndent`
a {
Expand Down
5 changes: 4 additions & 1 deletion lib/rules/hue-degree-notation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ const meta = {
};

const HUE_FIRST_ARG_FUNCS = ['hsl', 'hsla', 'hwb'];
const HUE_THIRD_ARG_FUNCS = ['lch'];
const HUE_THIRD_ARG_FUNCS = ['lch', 'oklch'];
const HUE_FUNCS = new Set([...HUE_FIRST_ARG_FUNCS, ...HUE_THIRD_ARG_FUNCS]);
const HAS_HUE_COLOR_FUNC = new RegExp(`\\b(?:${[...HUE_FUNCS].join('|')})\\(`, 'i');

/** @type {import('stylelint').Rule} */
const rule = (primary, _secondaryOptions, context) => {
Expand All @@ -36,6 +37,8 @@ const rule = (primary, _secondaryOptions, context) => {
if (!validOptions) return;

root.walkDecls((decl) => {
if (!HAS_HUE_COLOR_FUNC.test(decl.value)) return;

let needsFix = false;
const parsedValue = valueParser(getDeclarationValue(decl));

Expand Down
60 changes: 32 additions & 28 deletions lib/rules/media-feature-name-unit-allowed-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,49 @@ const rule = (primary) => {
mediaQueryList.forEach((mediaQuery) => {
if (isMediaQueryInvalid(mediaQuery)) return;

mediaQuery.walk((entry) => {
if (!isMediaFeaturePlain(entry.node) && !isMediaFeatureRange(entry.node)) {
return;
}
const initialState = {
mediaFeatureName: '',
/** @type {string[] | undefined} */
unitList: undefined,
};

mediaQuery.walk(({ node, state }) => {
if (!state) return;

const featureName = entry.node.getName();
const unitList = primaryUnitList(featureName);
if (isMediaFeaturePlain(node) || isMediaFeatureRange(node)) {
state.mediaFeatureName = node.getName();
state.unitList = primaryUnitList(state.mediaFeatureName);

if (!unitList) {
return;
}

entry.node.walk(({ node: childNode }) => {
if (!isTokenNode(childNode)) {
return;
}
if (!isTokenNode(node)) return;

const [tokenType, , startIndex, endIndex, parsedValue] = childNode.value;
const { mediaFeatureName, unitList } = state;

if (tokenType !== TokenType.Dimension) {
return;
}
if (!mediaFeatureName || !unitList) return;

if (unitList.includes(parsedValue.unit.toLowerCase())) {
return;
}
const [tokenType, , startIndex, endIndex, parsedValue] = node.value;

if (tokenType !== TokenType.Dimension) {
return;
}

if (unitList.includes(parsedValue.unit.toLowerCase())) {
return;
}

const atRuleIndex = atRuleParamIndex(atRule);
const atRuleIndex = atRuleParamIndex(atRule);

report({
message: messages.rejected(parsedValue.unit, featureName),
node: atRule,
index: atRuleIndex + startIndex,
endIndex: atRuleIndex + endIndex + 1,
result,
ruleName,
});
report({
message: messages.rejected(parsedValue.unit, mediaFeatureName),
node: atRule,
index: atRuleIndex + startIndex,
endIndex: atRuleIndex + endIndex + 1,
result,
ruleName,
});
});
}, initialState);
});
});
};
Expand Down
22 changes: 11 additions & 11 deletions lib/rules/media-feature-name-value-no-unknown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,38 +234,38 @@ const rule = (primary) => {
};

/** @type {State} */
const state = {
const initialState = {
mediaFeatureName: '',
mediaFeatureNameRaw: '',
};

parseMediaQuery(atRule).forEach((mediaQuery) => {
if (isMediaQueryInvalid(mediaQuery)) return;

mediaQuery.walk((entry) => {
if (!entry.state) return;
mediaQuery.walk(({ node, state }) => {
if (!state) return;

if (isMediaFeature(entry.node)) {
const mediaFeatureNameRaw = entry.node.getName();
if (isMediaFeature(node)) {
const mediaFeatureNameRaw = node.getName();
let mediaFeatureName = vendor.unprefixed(mediaFeatureNameRaw.toLowerCase());

// Unknown media feature names are handled by "media-feature-name-no-unknown".
if (!mediaFeatureNames.has(mediaFeatureName)) return;

mediaFeatureName = mediaFeatureName.replace(HAS_MIN_MAX_PREFIX, '');

entry.state.mediaFeatureName = mediaFeatureName;
entry.state.mediaFeatureNameRaw = mediaFeatureNameRaw;
state.mediaFeatureName = mediaFeatureName;
state.mediaFeatureNameRaw = mediaFeatureNameRaw;

return;
}

if (!entry.state.mediaFeatureName || !entry.state.mediaFeatureNameRaw) return;
if (!state.mediaFeatureName || !state.mediaFeatureNameRaw) return;

if (isMediaFeatureValue(entry.node)) {
checkMediaFeatureValue(entry.state, entry.node, reporter);
if (isMediaFeatureValue(node)) {
checkMediaFeatureValue(state, node, reporter);
}
}, state);
}, initialState);
});
});
};
Expand Down
6 changes: 1 addition & 5 deletions lib/rules/media-feature-range-notation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ const rule = (primary, _secondaryOptions, context) => {
mediaQueryList.forEach((mediaQuery) => {
if (isMediaQueryInvalid(mediaQuery)) return;

mediaQuery.walk((entry) => {
const node = entry.node;

mediaQuery.walk(({ node, parent }) => {
// Only look at plain and range notation media features
if (!isMediaFeatureRange(node) && !isMediaFeaturePlain(node)) return;

Expand All @@ -66,8 +64,6 @@ const rule = (primary, _secondaryOptions, context) => {
if (!rangeTypeMediaFeatureNames.has(unprefixedMediaFeature)) return;

if (context.fix && primary === 'context' && isMediaFeaturePlain(node)) {
const parent = entry.parent;

if (!isMediaFeature(parent)) return;

hasFixes = true;
Expand Down

0 comments on commit df0e7e4

Please sign in to comment.