Revision control

Copy as Markdown

Other Tools

/* 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");
const rollouts = require("./stylelint-rollouts.config");
function readFile(filePath) {
return fs
.readFileSync(filePath, { encoding: "utf-8" })
.split("\n")
.filter(p => p && !p.startsWith("#"));
}
const ignoreFiles = [
...readFile(
path.join(__dirname, "tools", "rewriting", "ThirdPartyPaths.txt")
),
...readFile(path.join(__dirname, "tools", "rewriting", "Generated.txt")),
];
module.exports = {
extends: ["stylelint-config-recommended"],
plugins: [
"./tools/lint/stylelint/stylelint-plugin-mozilla/index.mjs",
"@stylistic/stylelint-plugin",
"stylelint-use-logical",
],
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: [
"light-dark" /* Used for color-scheme dependent colors */,
"add" /* Used in mathml.css */,
"-moz-symbolic-icon" /* Used for GTK icons */,
],
},
],
"length-zero-no-unit": [
true,
{
ignore: ["custom-properties"],
},
],
"max-nesting-depth": [
3,
{
ignore: ["blockless-at-rules"],
},
],
"no-descending-specificity": null,
"no-duplicate-selectors": null,
"property-no-unknown": [
true,
{
ignoreProperties: [
// overflow-clip-box is Gecko-specific and not exposed to web
// content. Might be replaced with overflow-clip-margin, see:
"overflow-clip-box",
"overflow-clip-box-block",
"overflow-clip-box-inline",
],
},
],
/*
* 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"],
},
],
"selector-pseudo-element-no-unknown": [
true,
{
ignorePseudoElements: ["slider-track", "slider-fill", "slider-thumb"],
},
],
// stylelint fixes for the use-logical rule will be addressed in Bug 1996168
// Remove this line setting `csscontrols/use-logical` to null after implementing fixes
"csstools/use-logical": null,
"stylelint-plugin-mozilla/no-base-design-tokens": true,
"stylelint-plugin-mozilla/use-background-color-tokens": true,
"stylelint-plugin-mozilla/use-border-color-tokens": true,
"stylelint-plugin-mozilla/use-border-radius-tokens": true,
"stylelint-plugin-mozilla/use-font-size-tokens": true,
"stylelint-plugin-mozilla/use-font-weight-tokens": true,
"stylelint-plugin-mozilla/use-space-tokens": true,
"stylelint-plugin-mozilla/use-text-color-tokens": true,
"stylelint-plugin-mozilla/use-box-shadow-tokens": true,
"stylelint-plugin-mozilla/no-non-semantic-token-usage": true,
"stylelint-plugin-mozilla/use-size-tokens": true,
},
overrides: [
{
files: "*.scss",
customSyntax: "postcss-scss",
extends: "stylelint-config-recommended-scss",
},
{
files: [
"browser/components/aboutwelcome/**",
"browser/components/asrouter/**",
"browser/extensions/newtab/**",
],
customSyntax: "postcss-scss",
extends: "stylelint-config-standard-scss",
rules: {
"@stylistic/color-hex-case": "upper",
"@stylistic/indentation": 2,
"@stylistic/no-eol-whitespace": true,
"@stylistic/no-missing-end-of-source-newline": true,
"@stylistic/number-leading-zero": "always",
"@stylistic/number-no-trailing-zeros": true,
"@stylistic/string-quotes": [
"single",
{
avoidEscape: true,
},
],
"at-rule-disallowed-list": [
["debug", "warn", "error"],
{
message: "Clean up %s directives before committing",
},
],
"at-rule-no-vendor-prefix": null,
"color-function-notation": null,
"comment-empty-line-before": [
"always",
{
except: ["first-nested"],
ignore: ["after-comment", "stylelint-commands"],
},
],
"custom-property-empty-line-before": null,
"custom-property-pattern": null,
"declaration-block-no-duplicate-properties": true,
"declaration-block-no-redundant-longhand-properties": null,
"declaration-no-important": true,
"function-no-unknown": [
true,
{
ignoreFunctions: ["div"],
},
],
"function-url-no-scheme-relative": true,
"keyframes-name-pattern": null,
"media-feature-name-no-vendor-prefix": null,
"no-descending-specificity": null,
"property-disallowed-list": [
["margin-left", "margin-right"],
{
message: "Use margin-inline instead of %s",
},
],
"property-no-unknown": true,
"property-no-vendor-prefix": null,
"scss/dollar-variable-empty-line-before": null,
"scss/double-slash-comment-empty-line-before": [
"always",
{
except: ["first-nested"],
ignore: ["between-comments", "stylelint-commands", "inside-block"],
},
],
"selector-class-pattern": null,
"selector-no-vendor-prefix": null,
"value-keyword-case": null,
"value-no-vendor-prefix": null,
},
},
{
files: ["browser/extensions/newtab/**"],
rules: {
"declaration-property-value-disallowed-list": [
{
"font-size": [
"/^[0-9.]+(px|em|rem|%)$/",
"/^[0-9.]+$/",
"/^(small|medium|large|x-large|xx-large)$/",
],
"border-radius": [
"/^[0-9.]+(px|em|rem|%)$/",
"/^(small|medium|large|x-large|xx-large)$/",
],
// Validate to only allow variables and global values
"font-weight": [
"/^(?!var\\(|inherit$|initial$|unset$|revert$|revert-layer$).+$/",
],
[/^(margin|padding|inset|gap|row-gap|column-gap|grid-row-gap|grid-column-gap|top|right|bottom|left)($|-)/]:
["/[0-9.]+(px|em|rem)|\\$/"],
},
{
message:
"Avoid literal values. Use variables (e.g. var(--font-size-small)) or inherit/unset/etc.",
},
],
},
},
{
name: "design-token-rules-off",
files: [
// CSS files under browser/components/extensions are not using design tokens
"browser/components/extensions/**",
// Webcompat interventions are not expected to use design tokens
// They are intended to override existing styles for specific extension
"browser/extensions/webcompat/injections/css/**",
// Most of devtools does not use design tokens, so turn the appropriate rules off for devtools.
// Stylelint does not support negating the file glob within an overrides section,
// so these rules get re-enabled for some devtools files in the section below
"devtools/**",
// FXR is no longer maintained and is not expected to use design tokens
"browser/fxr/**",
// Android does not use design tokens
"mobile/android/**",
// Docs do not use design tokens
"docs/**",
// UA Widgets should not use design tokens
"toolkit/themes/shared/media/pipToggle.css",
"toolkit/themes/shared/media/videocontrols.css",
"toolkit/content/widgets/datetimebox.css",
"toolkit/content/widgets/marquee.css",
"toolkit/themes/shared/media/textrecognition.css",
// The contents of backup/content/archive.css are injected as inline CSS
// into the HTML backup archive files that exist on a user's file system
// and can be opened in any browser.
"browser/components/backup/content/archive.css",
],
rules: {
"stylelint-plugin-mozilla/use-background-color-tokens": null,
"stylelint-plugin-mozilla/use-border-color-tokens": null,
"stylelint-plugin-mozilla/use-border-radius-tokens": null,
"stylelint-plugin-mozilla/use-font-size-tokens": null,
"stylelint-plugin-mozilla/use-font-weight-tokens": null,
"stylelint-plugin-mozilla/use-space-tokens": null,
"stylelint-plugin-mozilla/use-text-color-tokens": null,
"stylelint-plugin-mozilla/use-box-shadow-tokens": null,
"stylelint-plugin-mozilla/no-non-semantic-token-usage": null,
"stylelint-plugin-mozilla/use-size-tokens": null,
},
},
{
name: "design-token-rules-on",
files: [
// Enable design token related rules only on the parts of devtools that can use them
"devtools/client/aboutdebugging/src/**",
],
rules: {
"stylelint-plugin-mozilla/use-background-color-tokens": true,
"stylelint-plugin-mozilla/use-border-color-tokens": true,
"stylelint-plugin-mozilla/use-border-radius-tokens": true,
"stylelint-plugin-mozilla/use-space-tokens": true,
"stylelint-plugin-mozilla/use-text-color-tokens": true,
"stylelint-plugin-mozilla/no-non-semantic-token-usage": true,
"stylelint-plugin-mozilla/use-size-tokens": true,
},
},
{
files: ["toolkit/**/*.css", "toolkit/**/*.scss"],
rules: {
"stylelint-plugin-mozilla/no-browser-refs-in-toolkit": true,
},
},
{
// non-logical properties make sense in devtools/ where physical positioning always makes sense
name: "logical-properties-rule-off",
files: ["devtools/**"],
rules: {
"csstools/use-logical": null,
},
},
// Rollouts should always be applied last in the overrides section
// to ensure that they take precedence over other overrides.
...rollouts,
],
};