Skip to content

Commit

Permalink
fix: Use relative paths with stylelint (#448)
Browse files Browse the repository at this point in the history
  • Loading branch information
JesseTatasciore authored Dec 16, 2024
1 parent b94a079 commit 2785184
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 6 deletions.
6 changes: 6 additions & 0 deletions lint/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ alias(
visibility = ["//visibility:public"],
)

alias(
name = "stylelint.compact-formatter",
actual = "//lint/js:stylelint.compact-formatter",
visibility = ["//visibility:public"],
)

bzl_library(
name = "eslint",
srcs = ["eslint.bzl"],
Expand Down
6 changes: 6 additions & 0 deletions lint/js/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ js_library(
visibility = ["//visibility:public"],
)

js_library(
name = "stylelint.compact-formatter",
srcs = ["stylelint.compactFormatter.mjs"],
visibility = ["//visibility:public"],
)

138 changes: 138 additions & 0 deletions lint/js/stylelint.compactFormatter.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Fork of 'compactFormatter' plugin, changed so that it prints relative paths.
// 3 files have been combined into 1
// https://github.com/stylelint/stylelint/blob/b2c99cef764643f3bd9539b34cdec58af882db88/lib/formatters/compactFormatter.mjs
// https://github.com/stylelint/stylelint/blob/b2c99cef764643f3bd9539b34cdec58af882db88/lib/formatters/preprocessWarnings.mjs
// https://github.com/stylelint/stylelint/blob/b2c99cef764643f3bd9539b34cdec58af882db88/lib/constants.mjs


/***************************************************************************************************************
* The following is vendored from:
* https://github.com/stylelint/stylelint/blob/b2c99cef764643f3bd9539b34cdec58af882db88/lib/constants.mjs
***************************************************************************************************************/
import { relative, sep } from 'node:path';

export const DEFAULT_CACHE_LOCATION = './.stylelintcache';
export const CACHE_STRATEGY_METADATA = 'metadata';
export const CACHE_STRATEGY_CONTENT = 'content';
export const DEFAULT_CACHE_STRATEGY = CACHE_STRATEGY_METADATA;

export const DEFAULT_IGNORE_FILENAME = '.stylelintignore';

export const DEFAULT_FORMATTER = 'string';

// NOTE: Partially based on `sysexits.h`.
export const EXIT_CODE_SUCCESS = 0;
export const EXIT_CODE_FATAL_ERROR = 1;
export const EXIT_CODE_LINT_PROBLEM = 2;
export const EXIT_CODE_INVALID_USAGE = 64;
export const EXIT_CODE_INVALID_CONFIG = 78;

export const RULE_NAME_ALL = 'all';

export const SEVERITY_ERROR = 'error';
export const SEVERITY_WARNING = 'warning';
export const DEFAULT_SEVERITY = SEVERITY_ERROR;

/***************************************************************************************************************
* The following is vendored from:
* https://github.com/stylelint/stylelint/blob/b2c99cef764643f3bd9539b34cdec58af882db88/lib/formatters/preprocessWarnings.mjs
***************************************************************************************************************/
/** @import {LintResult} from 'stylelint' */
/** @typedef {LintResult['parseErrors'][0]} ParseError */
/** @typedef {LintResult['warnings'][0]} Warning */
/** @typedef {Warning['severity']} Severity */

/**
* Preprocess warnings in a given lint result.
* Note that this function has a side-effect.
*
* @param {LintResult} result
* @returns {LintResult}
*/
export function preprocessWarnings(result) {
for (const error of result.parseErrors || []) {
result.warnings.push(parseErrorToWarning(error));
}

for (const warning of result.warnings) {
warning.severity = normalizeSeverity(warning);
}

result.warnings.sort(byLocationOrder);

return result;
}

/**
* @param {ParseError} error
* @returns {Warning}
*/
function parseErrorToWarning(error) {
return {
line: error.line,
column: error.column,
rule: error.stylelintType,
severity: SEVERITY_ERROR,
text: `${error.text} (${error.stylelintType})`,
};
}

/**
* @param {Warning} warning
* @returns {Severity}
*/
function normalizeSeverity(warning) {
// NOTE: Plugins may add a warning without severity, for example,
// by directly using the PostCSS `Result#warn()` API.
return warning.severity || DEFAULT_SEVERITY;
}

/**
* @param {Warning} a
* @param {Warning} b
* @returns {number}
*/
function byLocationOrder(a, b) {
// positionless first
if (!a.line && b.line) return -1;

// positionless first
if (a.line && !b.line) return 1;

if (a.line < b.line) return -1;

if (a.line > b.line) return 1;

if (a.column < b.column) return -1;

if (a.column > b.column) return 1;

return 0;
}

/***************************************************************************************************************
* The following is vendored from:
* https://github.com/stylelint/stylelint/blob/b2c99cef764643f3bd9539b34cdec58af882db88/lib/formatters/compactFormatter.mjs
***************************************************************************************************************/
/**
* @type {import('stylelint').Formatter}
* @param {import('stylelint').Warning[]} messages
* @param {string} source
* @param {string} cwd
*/
export default function compactFormatter(results, returnValue) {
return results
.flatMap((result) => {
const { warnings } = preprocessWarnings(result);

return warnings.map(
(warning) =>
`${relative((returnValue && returnValue.cwd) || process.cwd(), result.source).split(sep).join('/')}: ` +
`line ${warning.line}, ` +
`col ${warning.column}, ` +
`${warning.severity} - ` +
`${warning.text}`,
);
})
.join('\n');
}
25 changes: 19 additions & 6 deletions lint/stylelint.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ load("//lint/private:lint_aspect.bzl", "LintOptionsInfo", "filter_srcs", "output

_MNEMONIC = "AspectRulesLintStylelint"

def _gather_inputs(ctx, srcs):
def _gather_inputs(ctx, srcs, files = []):
inputs = copy_files_to_bin_actions(ctx, srcs)

# Add the config file along with any deps it has on npm packages
if "gather_files_from_js_providers" in dir(js_lib_helpers):
# rules_js 1.x
js_inputs = js_lib_helpers.gather_files_from_js_providers(
[ctx.attr._config_file],
[ctx.attr._config_file] + files,
include_transitive_sources = True,
include_declarations = False,
include_npm_linked_packages = True,
)
else:
# rules_js 2.x
js_inputs = js_lib_helpers.gather_files_from_js_infos(
[ctx.attr._config_file],
[ctx.attr._config_file] + files,
include_sources = True,
include_transitive_sources = True,
include_types = False,
Expand All @@ -67,7 +67,7 @@ def _gather_inputs(ctx, srcs):
)
return depset(inputs, transitive = [js_inputs])

def stylelint_action(ctx, executable, srcs, stderr, exit_code = None, env = {}, options = []):
def stylelint_action(ctx, executable, srcs, stderr, exit_code = None, env = {}, options = [], format = None):
"""Spawn stylelint as a Bazel action
Args:
Expand All @@ -85,6 +85,7 @@ def stylelint_action(ctx, executable, srcs, stderr, exit_code = None, env = {},
78 - invalid configuration file
env: environment variables for stylelint
options: additional command-line arguments
format: a formatter to add as a command line argument
"""
outputs = [stderr]

Expand All @@ -100,8 +101,15 @@ def stylelint_action(ctx, executable, srcs, stderr, exit_code = None, env = {},
# Create empty file on success, as Bazel expects one
command = "{stylelint} $@ && touch {stderr}"

file_inputs = []
if type(format) == "string":
args.add_all(["--formatter", format])
elif format != None:
args.add_all(["--custom-formatter", "../../../" + format.files.to_list()[0].path])
file_inputs.append(format)

ctx.actions.run_shell(
inputs = _gather_inputs(ctx, srcs),
inputs = _gather_inputs(ctx, srcs, file_inputs),
outputs = outputs,
command = command.format(stylelint = executable._stylelint.path, stderr = stderr.path),
arguments = [args],
Expand Down Expand Up @@ -180,7 +188,7 @@ def _stylelint_aspect_impl(target, ctx):
stylelint_action(ctx, ctx.executable, files_to_lint, outputs.human.out, outputs.human.exit_code, options = color_options)

# TODO(alex): if we run with --fix, this will report the issues that were fixed. Does a machine reader want to know about them?
stylelint_action(ctx, ctx.executable, files_to_lint, outputs.machine.out, outputs.machine.exit_code, options = ["--formatter", "compact"])
stylelint_action(ctx, ctx.executable, files_to_lint, outputs.machine.out, outputs.machine.exit_code, format = ctx.attr._compact_formatter)

return [info]

Expand Down Expand Up @@ -215,6 +223,11 @@ def lint_stylelint_aspect(binary, config, rule_kinds = ["css_library"], filegrou
default = config,
allow_files = True,
),
"_compact_formatter": attr.label(
default = "@aspect_rules_lint//lint:stylelint.compact-formatter",
allow_single_file = True,
cfg = "exec",
),
"_patcher": attr.label(
default = "@aspect_rules_lint//lint/private:patcher",
executable = True,
Expand Down

0 comments on commit 2785184

Please sign in to comment.