From 4237aaecd2b87f40df8538272ad737635f4bd15c Mon Sep 17 00:00:00 2001 From: Rob Lemley Date: Wed, 24 May 2023 18:49:33 +0000 Subject: [PATCH] Bug 1832130 - Port bug 1508369: Add stylelint to mach commlint. r=aleca Differential Revision: https://phabricator.services.mozilla.com/D178832 --HG-- rename : .eslintignore => .stylelintignore extra : moz-landing-system : lando --- .eslintignore | 11 ++ .stylelintignore | 33 +++++ .stylelintrc.js | 239 ++++++++++++++++++++++++++++++++ tools/lint/commlint/__init__.py | 13 ++ tools/lint/stylelint.yml | 17 +++ 5 files changed, 313 insertions(+) create mode 100644 .stylelintignore create mode 100644 .stylelintrc.js create mode 100644 tools/lint/stylelint.yml diff --git a/.eslintignore b/.eslintignore index e99e0547de..1508dd0bfd 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,14 @@ +# Please DO NOT add more third party files to this file. +# They should be added to tools/rewriting/ThirdPartyPaths.txt instead. +# +# Please also DO NOT add generated files that are for some reason checked +# into source - add them to tools/rewriting/Generated.txt instead. + +# This file should only be used for exclusions where we have: +# - preprocessed files +# - intentionally invalid files +# - build directories and other items that we need to ignore + # Temporarily disabled, see bug 1605845 *.xhtml diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000000..ab7936902d --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,33 @@ +# Please DO NOT add more third party files to this file. +# They should be added to tools/rewriting/ThirdPartyPaths.txt instead. +# +# Please also DO NOT add generated files that are for some reason checked +# into source - add them to tools/rewriting/Generated.txt instead. + +# This file should only be used for exclusions where we have: +# - preprocessed files +# - intentionally invalid files +# - build directories and other items that we need to ignore + + # Always ignore node_modules. +**/node_modules/**/*.* +# Exclude expected objdirs. +obj*/** + +# Exclude mozilla directory, this one is checked separately +mozilla/** + +# These directories don't contain any js and are not meant to +config/** +other-licenses/** +testing/** + +# We ignore all these directories by default, until we get them enabled. +# If you are enabling a directory, please add directory specific exclusions +# below. +build/** +suite/** + +# Empty file to ignore +mail/components/im/messages/simple/Variants/Normal.css + diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000000..722ff7f9ad --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,239 @@ +/* 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/. */ + +/* eslint-env node */ + +"use strict"; + +const fs = require("fs"); +const path = require("path"); + +function readFile(path) { + return fs + .readFileSync(path, { encoding: "utf-8" }) + .split("\n") + .filter(p => p && !p.startsWith("#")) + .map(p => p.replace(/^comm\//, "")); +} + +const ignoreFiles = [ + ...readFile(path.join(__dirname, "tools", "lint", "ThirdPartyPaths.txt")), + ...readFile(path.join(__dirname, "tools", "lint", "Generated.txt")), +]; + +module.exports = { + extends: ["stylelint-config-recommended"], + ignoreFiles, + rules: { + /* Disabled because of `-moz-element(#foo)` which gets misparsed. */ + "color-no-invalid-hex": null, + "font-family-no-missing-generic-family-keyword": [ + true, + { + ignoreFontFamilies: [ + "-moz-button", + "-moz-field", + "-moz-fixed", + "-moz-list", + "caption", + ], + }, + ], + + "function-no-unknown": [ + true, + { + ignoreFunctions: [ + "-moz-image-rect" /* Used for cropping images */, + "add" /* Used in mathml.css */, + ], + }, + ], + + "no-descending-specificity": null, + "no-duplicate-selectors": null, + + "property-no-unknown": [ + true, + { + ignoreProperties: ["overflow-clip-box"], + }, + ], + + /* + * XXXgijs: we would like to enable this, but we can't right now. + * This is because Gecko uses a number of custom pseudoclasses, + * and stylelint assumes that for `:unknown-pseudoclass(foo)`, + * `foo` should be a known type. + * This is tedious but workable for things like `-moz-locale-dir` where + * the set of acceptable values (ltr/rtl) is small. + * However, for tree cells, the set of values is unlimited (ie + * user-defined, based on atoms sent by the JS tree view APIs). + * There does not appear to be a way to exempt the contents of these + * unknown pseudoclasses, and as a result, this rule is not + * usable for us. The 'type' only includes the contents of the + * pseudoclass, not the pseudo itself, so we can't filter based on the + * pseudoclass either. + * Ideally, we would either create an option to the builtin rule + * in stylelint itself, or mimic the rule but exempt these, or + * add parser support for our custom pseudoclasses. + * + * For now, we just disable this rule. + */ + "selector-type-no-unknown": null, + /* + * See above - if we enabled this rule, we'd have to allow for a number + * of custom elements we use, which are listed here: + "selector-type-no-unknown": [ + true, + { + ignore: ["custom-elements"], + ignoreTypes: [ + // Modern custom element / storybooked components: + /^moz-/, + // moz-locale-dir trips this rule for some reason: + "rtl", + "ltr", + // Migrated XBL elements not part of core XUL that we use at the moment: + "findbar", + "panelmultiview", + "panelview", + "popupnotification", + "popupnotificationcontent", + // Legacy XUL elements: + // (the commented out ones used to be a thing and aren't used in-tree anymore) + "arrowscrollbox", + "box", + // "broadcaster", + // "broadcasterset", + "button", + "browser", + "checkbox", + "caption", + // clicktoscroll + // colorpicker + // column + // columns + "commandset", + "command", + // conditions + // content + // datepicker + "deck", + "description", + "dialog", + // dialogheader + "dropmarker", + "editor", + // grid + // grippy + "groupbox", + "hbox", + // iframe + // image + "key", + "keyset", + // label + "listbox", + // listcell + // listcol + // listcols + // listhead + // listheader + "listitem", + // member + "menu", + "menubar", + "menucaption", + "menuitem", + "menulist", + "menupopup", + "menuseparator", + "notification", + "notificationbox", + "observes", + // overlay + // page + "panel", + // param + "popupset", + // preference + // preferences + // prefpane + // prefwindow + // progressmeter + // query + // queryset + "radio", + "radiogroup", + // resizer + "richlistbox", + "richlistitem", + // row + // rows + // rule + // scale + // script + "scrollbar", + "scrollbox", + "scrollcorner", + "separator", + "spacer", + // spinbuttons + "splitter", + "stack", + // statusbar + // statusbarpanel + "stringbundle", + "stringbundleset", + "tab", + "tabbox", + "tabpanel", + "tabpanels", + "tabs", + // template + // textnode + "textbox", + // timepicker + "titlebar", + "toolbar", + "toolbarbutton", + // toolbargrippy + "toolbaritem", + "toolbarpalette", + "toolbarpaletteitem", + "toolbarseparator", + "toolbarset", + "toolbarspacer", + "toolbarspring", + "toolbartabstop", + "toolbox", + "tooltip", + "tree", + "treecell", + "treechildren", + "treecol", + "treecols", + "treeitem", + "treerow", + "treeseparator", + // triple + "vbox", + // where + "window", + "wizard", + "wizardpage", + ], + }, + ], + */ + + "selector-pseudo-class-no-unknown": [ + true, + { + ignorePseudoClasses: ["popover-open"], + }, + ], + }, +}; diff --git a/tools/lint/commlint/__init__.py b/tools/lint/commlint/__init__.py index 2fc2fd3cec..19d887e109 100644 --- a/tools/lint/commlint/__init__.py +++ b/tools/lint/commlint/__init__.py @@ -62,6 +62,19 @@ def eslint_wrapper(paths, config, **lintargs): return rv +def stylelint_wrapper(paths, config, **lintargs): + comm_root = Path(lintargs["root"]) / "comm" + + ignore_file = str(comm_root / ".stylelintignore") + lintargs.setdefault("extra_args", []) + lintargs["extra_args"].extend(["--ignore-path", ignore_file]) + + with pushd(comm_root): + rv = lint_wrapper(paths, config, **lintargs) + + return rv + + def black_lint(paths, config, fix=None, **lintargs): from python.black import run_black diff --git a/tools/lint/stylelint.yml b/tools/lint/stylelint.yml new file mode 100644 index 0000000000..f23297cd26 --- /dev/null +++ b/tools/lint/stylelint.yml @@ -0,0 +1,17 @@ +--- +stylelint: + description: CSS linter + # Stylelint infra handles its own path filtering, so just include cwd + include: ['.'] + exclude: [] + extensions: ['css'] + support-files: + - 'package.json' + - 'comm/**/.stylelintrc.js' + - 'comm/.stylelintignore' + - 'tools/lint/stylelint/**' + type: external + stylelint-rc: comm/.stylelintrc.js + payload: commlint:stylelint_wrapper + wraps: stylelint:lint + setup: stylelint:setup