Skip to content

Fix ruleMetadata missing data when first file has no rules #9134

@adalinesimonian

Description

@adalinesimonian

What minimal example or steps are needed to reproduce the bug?

Create two CSS files and lint them via the Node API:

other.css:

body {
  margin: 0;
}

src/test.css:

a {
  color: #fff;
}
import stylelint from 'stylelint';

// Lint with the file that doesn't match any override listed first.
const result = await stylelint.lint({
  files: ['other.css', 'src/test.css'],
});

console.log(result.ruleMetadata);
// => {}, but should contain color-hex-length and block-no-empty metadata

What minimal configuration is needed to reproduce the bug?

{
  "rules": {},
  "overrides": [
    {
      "files": ["src/**/*.css"],
      "rules": {
        "color-hex-length": "long",
        "block-no-empty": true
      }
    }
  ]
}

How did you run Stylelint?

Via the Node API using stylelint.lint() with an explicit file list as shown above. The bug also reproduces with globs when the non-matching file sorts first alphabetically, e.g.:

const result = await stylelint.lint({ files: ['**/*.css'] });

Which Stylelint-related dependencies are you using?

{
  "stylelint": "^17.4.0"
}

What did you expect to happen?

result.ruleMetadata should contain metadata for all rules that ran during the lint, regardless of file order. Linting ["other.css", "src/test.css"] should produce the same ruleMetadata as ["src/test.css", "other.css"].

What actually happened?

ruleMetadata is {} when the first file in the list has no rules applied to it. The metadata from subsequent files is discarded.

File order ruleMetadata
["other.css"] {} - correct
["src/test.css"] {color-hex-length: ..., block-no-empty: ...} - correct
["src/test.css", "other.css"] {color-hex-length: ..., block-no-empty: ...} - correct
["other.css", "src/test.css"] {} - bug
["**/*.css"] {} - bug, other.css sorts first

Do you have a proposal to fix the bug?

In lib/prepareReturnValue.mjs, getRuleMetadata destructures only the first element of lintResults:

/**
 * @param {LintResult[]} lintResults
 */
function getRuleMetadata(lintResults) {
	const [lintResult] = lintResults;

	if (lintResult === undefined) return {};

	if (lintResult._postcssResult === undefined) return {};

	return lintResult._postcssResult.stylelint.ruleMetadata;
}

It should probably merge metadata across all results instead:

/**
 * @param {LintResult[]} lintResults
 */
function getRuleMetadata(lintResults) {
	const merged = {};

	for (const lintResult of lintResults) {
		if (lintResult?._postcssResult === undefined) continue;

		Object.assign(merged, lintResult._postcssResult.stylelint.ruleMetadata);
	}

	return merged;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: wipis being worked on by someone

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions