Bug 1606785 - Enable Prettier for CSS files r=desktop-theme-reviewers,Standard8,frontend-codestyle-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D248105
This commit is contained in:
committed by
hjones@mozilla.com
parent
baa5d72bbd
commit
ec5fa1d4c0
@@ -8,6 +8,7 @@
|
||||
!*.xhtml
|
||||
!*.html
|
||||
!*.ts
|
||||
!*.css
|
||||
|
||||
# Prettier currently fails to parse this.
|
||||
toolkit/components/extensions/types/ext-tabs-base.d.ts
|
||||
@@ -1256,6 +1257,91 @@ toolkit/components/uniffi-bindgen-gecko-js/components/generated/*
|
||||
# test sourcemaps.
|
||||
devtools/client/inspector/rules/test/doc_sourcemaps2.css
|
||||
|
||||
##############################################################################
|
||||
# The list below is copied from .stylelintignore. Prettier doesn't currently
|
||||
# support multiple ignore files or dynamic ignore configurations.
|
||||
# When this is implemented, we'll update the configuration below (bug 1825508)
|
||||
##############################################################################
|
||||
|
||||
# These files are generated in some way.
|
||||
browser/components/pocket/content/panels/css/main.compiled.css
|
||||
browser/components/aboutwelcome/**/*.css
|
||||
browser/components/asrouter/**/*.css
|
||||
browser/extensions/newtab/**/*.css
|
||||
|
||||
# Note that the debugger has its own stylelint setup, but that currently
|
||||
# produces errors. Bug 1831302 tracks making this better
|
||||
devtools/client/debugger/src/components/PrimaryPanes/Outline.css
|
||||
devtools/client/debugger/src/components/PrimaryPanes/Sources.css
|
||||
devtools/client/debugger/src/components/shared/AccessibleImage.css
|
||||
devtools/client/debugger/src/utils/editor/source-editor.css
|
||||
devtools/client/debugger/test/mochitest/examples/
|
||||
|
||||
# These get their sourcemap annotations autofixed, though they produce
|
||||
# no errors at all.
|
||||
devtools/client/inspector/rules/test/doc_sourcemaps.css
|
||||
|
||||
# This is intended to simulate a css file generated from a scss file in order to
|
||||
# test sourcemaps.
|
||||
devtools/client/inspector/rules/test/doc_sourcemaps2.css
|
||||
|
||||
# Some of these produce parse errors, some have sourcemaps modified.
|
||||
# They're tests, so let's just ignore all of them:
|
||||
devtools/client/inspector/computed/test/doc_sourcemaps.css
|
||||
devtools/client/inspector/rules/test/doc_invalid_sourcemap.css
|
||||
devtools/client/shared/sourceeditor/test/css_statemachine_testcases.css
|
||||
devtools/client/webconsole/test/browser/*.css
|
||||
|
||||
# Style editor tests check how it copes with invalid or "special" CSS,
|
||||
# so don't try to "fix" those.
|
||||
devtools/client/styleeditor/test/
|
||||
|
||||
# These are empty or have funky charsets
|
||||
dom/base/test/bug466409-empty.css
|
||||
dom/encoding/test/file_utf16_be_bom.css
|
||||
dom/encoding/test/file_utf16_le_bom.css
|
||||
dom/security/test/cors/file_cors_logging_test.html.css
|
||||
dom/tests/mochitest/general/cssA.css
|
||||
dom/tests/mochitest/general/cssC.css
|
||||
|
||||
# These are test-only and cause us to complain about font families or
|
||||
# similar, but we don't want to touch these tests at this point.
|
||||
dom/security/test/csp/file_CSP.css
|
||||
dom/security/test/sri/style2.css
|
||||
dom/xml/test/old/docbook.css
|
||||
dom/xml/test/old/toc/book.css
|
||||
dom/xml/test/old/toc/toc.css
|
||||
|
||||
# Tests we don't want to modify at this point:
|
||||
layout/base/tests/stylesheet_change_events.css
|
||||
layout/inspector/tests/bug856317.css
|
||||
layout/inspector/tests/chrome/test_bug467669.css
|
||||
layout/inspector/tests/chrome/test_bug708874.css
|
||||
layout/style/test/gtest/example.css
|
||||
layout/style/test/mapped2.css
|
||||
layout/style/test/unstyled-frame.css
|
||||
|
||||
# Bug 1893763
|
||||
mobile/android/android-components/components/feature/readerview/src/main/assets/extensions/readerview/readerview.css
|
||||
# Three dashes at top of file (for Jekyll?) cause syntax error:
|
||||
mobile/android/android-components/docs/assets/main.scss
|
||||
|
||||
# Empty test files:
|
||||
netwerk/test/mochitests/test1.css
|
||||
netwerk/test/mochitests/test2.css
|
||||
|
||||
# Has substitution gunk in it:
|
||||
python/mozbuild/mozbuild/test/backend/data/build/foo.css
|
||||
|
||||
# This is third-party in a way:
|
||||
toolkit/components/pdfjs/content/web/debugger.css
|
||||
toolkit/components/pdfjs/content/web/viewer.css
|
||||
toolkit/components/pdfjs/content/web/viewer-geckoview.css
|
||||
build/pgo/blueprint/**/*.css
|
||||
|
||||
# Ignore web-platform tests as they are not necessarily under our control.
|
||||
testing/web-platform/tests/
|
||||
|
||||
##############################################################################
|
||||
# The list below is copied from ThirdPartyPaths.txt. Prettier doesn't currently
|
||||
# support multiple ignore files or dynamic ignore configurations.
|
||||
|
||||
2
.prettierignore-css
Normal file
2
.prettierignore-css
Normal file
@@ -0,0 +1,2 @@
|
||||
# When running Prettier via ESlint ignore these filetypes.
|
||||
*.css
|
||||
9
.prettierignore-non-css
Normal file
9
.prettierignore-non-css
Normal file
@@ -0,0 +1,9 @@
|
||||
# When running Prettier via Stylelint ignore these filetypes.
|
||||
*.js
|
||||
*.json
|
||||
*.jsx
|
||||
*.mjs
|
||||
*.sjs
|
||||
*.xhtml
|
||||
*.html
|
||||
*.ts
|
||||
@@ -10,4 +10,14 @@ module.exports = {
|
||||
printWidth: 80,
|
||||
tabWidth: 2,
|
||||
trailingComma: "es5",
|
||||
overrides: [
|
||||
{
|
||||
files: "*.css",
|
||||
options: {
|
||||
parser: "css",
|
||||
// Using a larger printWidth to avoid wrapping selectors.
|
||||
printWidth: 160,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -97,6 +97,7 @@ python/mozbuild/mozbuild/test/backend/data/build/foo.css
|
||||
toolkit/components/pdfjs/content/web/debugger.css
|
||||
toolkit/components/pdfjs/content/web/viewer.css
|
||||
toolkit/components/pdfjs/content/web/viewer-geckoview.css
|
||||
build/pgo/blueprint/**/*.css
|
||||
|
||||
# Ignore web-platform tests as they are not necessarily under our control.
|
||||
testing/web-platform/tests/
|
||||
|
||||
@@ -158,6 +158,7 @@ def setup_vscode(command_context, interactive):
|
||||
"json",
|
||||
"jsonc",
|
||||
"html",
|
||||
"css",
|
||||
]
|
||||
for lang in prettier_languages:
|
||||
new_settings[f"[{lang}]"] = {
|
||||
|
||||
@@ -533,6 +533,7 @@ file-perm:
|
||||
- '**/*.c'
|
||||
- '**/*.cc'
|
||||
- '**/*.cpp'
|
||||
- '**/*.css'
|
||||
- '**/*.flac'
|
||||
- '**/*.h'
|
||||
- '**/*.html'
|
||||
|
||||
@@ -14,7 +14,7 @@ sys.path.append(os.path.join(os.path.dirname(__file__), "eslint"))
|
||||
from mozbuild.nodeutil import find_node_executable
|
||||
from mozlint import result
|
||||
|
||||
from eslint import setup_helper
|
||||
from eslint import prettier_utils, setup_helper
|
||||
|
||||
ESLINT_ERROR_MESSAGE = """
|
||||
An error occurred running eslint. Please check the following error messages:
|
||||
@@ -32,16 +32,6 @@ mach eslint --setup
|
||||
and try again.
|
||||
""".strip()
|
||||
|
||||
PRETTIER_ERROR_MESSAGE = """
|
||||
An error occurred running prettier. Please check the following error messages:
|
||||
|
||||
{}
|
||||
""".strip()
|
||||
|
||||
PRETTIER_FORMATTING_MESSAGE = (
|
||||
"This file needs formatting with Prettier (use 'mach lint --fix <path>')."
|
||||
)
|
||||
|
||||
|
||||
def setup(root, **lintargs):
|
||||
setup_helper.set_project_root(root)
|
||||
@@ -123,6 +113,8 @@ def lint(paths, config, binary=None, fix=None, rules=[], setup=None, **lintargs)
|
||||
),
|
||||
"--list-different",
|
||||
"--no-error-on-unmatched-pattern",
|
||||
"--ignore-path=.prettierignore",
|
||||
"--ignore-path=.prettierignore-css",
|
||||
]
|
||||
+ extra_args
|
||||
# Prettier does not support exclude arguments.
|
||||
@@ -134,7 +126,7 @@ def lint(paths, config, binary=None, fix=None, rules=[], setup=None, **lintargs)
|
||||
if fix:
|
||||
cmd_args.append("--write")
|
||||
|
||||
prettier_result = run_prettier(cmd_args, config, fix)
|
||||
prettier_result = prettier_utils.run_prettier(cmd_args, config, fix)
|
||||
if prettier_result == 1:
|
||||
return prettier_result
|
||||
|
||||
@@ -203,99 +195,3 @@ def run(cmd_args, config):
|
||||
results.append(result.from_config(config, **err))
|
||||
|
||||
return {"results": results, "fixed": fixed}
|
||||
|
||||
|
||||
def run_prettier(cmd_args, config, fix):
|
||||
shell = False
|
||||
if is_windows():
|
||||
# The eslint binary needs to be run from a shell with msys
|
||||
shell = True
|
||||
encoding = "utf-8"
|
||||
|
||||
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
proc = subprocess.Popen(
|
||||
cmd_args, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
signal.signal(signal.SIGINT, orig)
|
||||
|
||||
try:
|
||||
output, errors = proc.communicate()
|
||||
except KeyboardInterrupt:
|
||||
proc.kill()
|
||||
return {"results": [], "fixed": 0}
|
||||
|
||||
results = []
|
||||
|
||||
if errors:
|
||||
errors = errors.decode(encoding, "replace").strip().split("\n")
|
||||
errors = [
|
||||
error
|
||||
for error in errors
|
||||
# Unknown options are not an issue for Prettier, this avoids
|
||||
# errors during tests.
|
||||
if not ("Ignored unknown option" in error)
|
||||
]
|
||||
if len(errors):
|
||||
results.append(
|
||||
result.from_config(
|
||||
config,
|
||||
**{
|
||||
"name": "eslint",
|
||||
"path": os.path.abspath("."),
|
||||
"message": PRETTIER_ERROR_MESSAGE.format("\n".join(errors)),
|
||||
"level": "error",
|
||||
"rule": "prettier",
|
||||
"lineno": 0,
|
||||
"column": 0,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
if not output:
|
||||
# If we have errors, but no output, we assume something really bad happened.
|
||||
if errors and len(errors):
|
||||
return {"results": results, "fixed": 0}
|
||||
|
||||
return {"results": [], "fixed": 0} # no output means success
|
||||
|
||||
output = output.decode(encoding, "replace").splitlines()
|
||||
|
||||
fixed = 0
|
||||
|
||||
if fix:
|
||||
# When Prettier is running in fix mode, it outputs the list of files
|
||||
# that have been fixed, so sum them up here.
|
||||
# If it can't fix files, it will throw an error, which will be handled
|
||||
# above.
|
||||
fixed = len(output)
|
||||
else:
|
||||
# When in "check" mode, Prettier will output the list of files that
|
||||
# need changing, so we'll wrap them in our result structure here.
|
||||
for file in output:
|
||||
if not file:
|
||||
continue
|
||||
|
||||
file = os.path.abspath(file)
|
||||
results.append(
|
||||
result.from_config(
|
||||
config,
|
||||
**{
|
||||
"name": "eslint",
|
||||
"path": file,
|
||||
"message": PRETTIER_FORMATTING_MESSAGE,
|
||||
"level": "error",
|
||||
"rule": "prettier",
|
||||
"lineno": 0,
|
||||
"column": 0,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
return {"results": results, "fixed": fixed}
|
||||
|
||||
|
||||
def is_windows():
|
||||
return (
|
||||
os.environ.get("MSYSTEM") in ("MINGW32", "MINGW64")
|
||||
or "MOZILLABUILD" in os.environ
|
||||
)
|
||||
|
||||
117
tools/lint/eslint/prettier_utils.py
Normal file
117
tools/lint/eslint/prettier_utils.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
|
||||
from mozlint import result
|
||||
|
||||
PRETTIER_ERROR_MESSAGE = """
|
||||
An error occurred running prettier. Please check the following error messages:
|
||||
|
||||
{}
|
||||
""".strip()
|
||||
|
||||
PRETTIER_FORMATTING_MESSAGE = (
|
||||
"This file needs formatting with Prettier (use 'mach lint --fix <path>')."
|
||||
)
|
||||
|
||||
|
||||
def run_prettier(cmd_args, config, fix):
|
||||
shell = False
|
||||
if is_windows():
|
||||
# The eslint binary needs to be run from a shell with msys
|
||||
shell = True
|
||||
encoding = "utf-8"
|
||||
|
||||
orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
proc = subprocess.Popen(
|
||||
cmd_args, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
signal.signal(signal.SIGINT, orig)
|
||||
|
||||
try:
|
||||
output, errors = proc.communicate()
|
||||
except KeyboardInterrupt:
|
||||
proc.kill()
|
||||
return {"results": [], "fixed": 0}
|
||||
|
||||
results = []
|
||||
|
||||
if errors:
|
||||
errors = errors.decode(encoding, "replace").strip().split("\n")
|
||||
errors = [
|
||||
error
|
||||
for error in errors
|
||||
# Unknown options are not an issue for Prettier, this avoids
|
||||
# errors during tests.
|
||||
if not ("Ignored unknown option" in error)
|
||||
]
|
||||
if len(errors):
|
||||
results.append(
|
||||
result.from_config(
|
||||
config,
|
||||
**{
|
||||
"name": "eslint",
|
||||
"path": os.path.abspath("."),
|
||||
"message": PRETTIER_ERROR_MESSAGE.format("\n".join(errors)),
|
||||
"level": "error",
|
||||
"rule": "prettier",
|
||||
"lineno": 0,
|
||||
"column": 0,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
if not output:
|
||||
# If we have errors, but no output, we assume something really bad happened.
|
||||
if errors and len(errors):
|
||||
return {"results": results, "fixed": 0}
|
||||
|
||||
return {"results": [], "fixed": 0} # no output means success
|
||||
|
||||
output = output.decode(encoding, "replace").splitlines()
|
||||
|
||||
fixed = 0
|
||||
|
||||
if fix:
|
||||
# When Prettier is running in fix mode, it outputs the list of files
|
||||
# that have been fixed, so sum them up here.
|
||||
# If it can't fix files, it will throw an error, which will be handled
|
||||
# above.
|
||||
fixed = len(output)
|
||||
else:
|
||||
# When in "check" mode, Prettier will output the list of files that
|
||||
# need changing, so we'll wrap them in our result structure here.
|
||||
for file in output:
|
||||
if not file:
|
||||
continue
|
||||
|
||||
file = os.path.abspath(file)
|
||||
results.append(
|
||||
result.from_config(
|
||||
config,
|
||||
**{
|
||||
"name": "eslint",
|
||||
"path": file,
|
||||
"message": PRETTIER_FORMATTING_MESSAGE,
|
||||
"level": "error",
|
||||
"rule": "prettier",
|
||||
"lineno": 0,
|
||||
"column": 0,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
return {"results": results, "fixed": fixed}
|
||||
|
||||
|
||||
def is_windows():
|
||||
return (
|
||||
os.environ.get("MSYSTEM") in ("MINGW32", "MINGW64")
|
||||
or "MOZILLABUILD" in os.environ
|
||||
)
|
||||
@@ -8,6 +8,7 @@ file-perm:
|
||||
- .c
|
||||
- .cc
|
||||
- .cpp
|
||||
- .css
|
||||
- .flac
|
||||
- .h
|
||||
- .html
|
||||
|
||||
@@ -23,7 +23,7 @@ if os.path.exists(thunderbird_excludes):
|
||||
|
||||
GLOBAL_EXCLUDES = ["**/node_modules", "tools/lint/test/files", ".hg", ".git"]
|
||||
|
||||
VALID_FORMATTERS = {"black", "clang-format", "eslint", "rustfmt"}
|
||||
VALID_FORMATTERS = {"black", "clang-format", "eslint", "rustfmt", "stylelint"}
|
||||
VALID_ANDROID_FORMATTERS = {"android-format"}
|
||||
|
||||
# Code-review bot must index issues from the whole codebase when pushing
|
||||
|
||||
@@ -12,7 +12,7 @@ import subprocess
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "eslint"))
|
||||
from eslint import setup_helper
|
||||
from eslint import prettier_utils, setup_helper
|
||||
from mozbuild.nodeutil import find_node_executable
|
||||
from mozlint import result
|
||||
|
||||
@@ -59,7 +59,7 @@ def lint(paths, config, binary=None, fix=None, rules=[], setup=None, **lintargs)
|
||||
modified_paths += [path]
|
||||
else:
|
||||
joined_path = os.path.join(path, "**", exts)
|
||||
if is_windows():
|
||||
if prettier_utils.is_windows():
|
||||
joined_path = joined_path.replace("\\", "/")
|
||||
modified_paths.append(joined_path)
|
||||
|
||||
@@ -76,6 +76,9 @@ def lint(paths, config, binary=None, fix=None, rules=[], setup=None, **lintargs)
|
||||
return 1
|
||||
|
||||
extra_args = lintargs.get("extra_args") or []
|
||||
result = {"results": [], "fixed": 0}
|
||||
|
||||
if not lintargs.get("formatonly", False):
|
||||
exclude_args = []
|
||||
for path in config.get("exclude", []):
|
||||
exclude_args.extend(
|
||||
@@ -112,12 +115,39 @@ def lint(paths, config, binary=None, fix=None, rules=[], setup=None, **lintargs)
|
||||
if result == 1:
|
||||
return result
|
||||
|
||||
# Then run Prettier
|
||||
cmd_args = (
|
||||
[
|
||||
binary,
|
||||
os.path.join(
|
||||
module_path, "node_modules", "prettier", "bin", "prettier.cjs"
|
||||
),
|
||||
"--list-different",
|
||||
"--no-error-on-unmatched-pattern",
|
||||
"--ignore-path=.prettierignore",
|
||||
"--ignore-path=.prettierignore-non-css",
|
||||
]
|
||||
# Prettier does not support exclude arguments.
|
||||
# + exclude_args
|
||||
+ paths
|
||||
)
|
||||
log.debug("Prettier command: {}".format(" ".join(cmd_args)))
|
||||
|
||||
if fix:
|
||||
cmd_args.append("--write")
|
||||
|
||||
prettier_result = prettier_utils.run_prettier(cmd_args, config, fix)
|
||||
if prettier_result == 1:
|
||||
return prettier_result
|
||||
|
||||
result["results"].extend(prettier_result["results"])
|
||||
result["fixed"] = result["fixed"] + prettier_result["fixed"]
|
||||
return result
|
||||
|
||||
|
||||
def run(cmd_args, config, fix):
|
||||
shell = False
|
||||
if is_windows():
|
||||
if prettier_utils.is_windows():
|
||||
# The stylelint binary needs to be run from a shell with msys
|
||||
shell = True
|
||||
encoding = "utf-8"
|
||||
@@ -185,10 +215,3 @@ def run(cmd_args, config, fix):
|
||||
results.append(result.from_config(config, **err))
|
||||
|
||||
return {"results": results, "fixed": fixed}
|
||||
|
||||
|
||||
def is_windows():
|
||||
return (
|
||||
os.environ.get("MSYSTEM") in ("MINGW32", "MINGW64")
|
||||
or "MOZILLABUILD" in os.environ
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user