tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit b0c5a2223b93f7d631914423d166290ddb77a3ff
parent d754e748bbe1327276fcd42a09d630067303907f
Author: dustin-jw <dwhisman@mozilla.com>
Date:   Thu, 16 Oct 2025 16:19:03 +0000

Bug 1988863 - Add a Stylelint rule to enforce using text-color tokens r=frontend-codestyle-reviewers,hjones

Differential Revision: https://phabricator.services.mozilla.com/D268022

Diffstat:
M.stylelintrc.js | 15+++++++++------
Adocs/code-quality/lint/linters/stylelint-plugin-mozilla/rules/use-text-color-tokens.rst | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstylelint-rollouts.config.js | 239+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/lint/stylelint/stylelint-plugin-mozilla/rules/index.mjs | 2++
Mtools/lint/stylelint/stylelint-plugin-mozilla/rules/no-base-design-tokens.mjs | 2--
Mtools/lint/stylelint/stylelint-plugin-mozilla/rules/use-border-color-tokens.mjs | 1-
Atools/lint/stylelint/stylelint-plugin-mozilla/rules/use-text-color-tokens.mjs | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools/lint/stylelint/stylelint-plugin-mozilla/tests/use-text-color-tokens.tests.mjs | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 551 insertions(+), 9 deletions(-)

diff --git a/.stylelintrc.js b/.stylelintrc.js @@ -270,12 +270,13 @@ module.exports = { }, ], "stylelint-plugin-mozilla/no-base-design-tokens": true, - "stylelint-plugin-mozilla/use-border-radius-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-background-color-tokens": true, + "stylelint-plugin-mozilla/use-text-color-tokens": true, }, overrides: [ @@ -416,12 +417,13 @@ module.exports = { "browser/components/backup/content/archive.css", ], rules: { - "stylelint-plugin-mozilla/use-border-radius-tokens": false, + "stylelint-plugin-mozilla/use-background-color-tokens": false, "stylelint-plugin-mozilla/use-border-color-tokens": false, + "stylelint-plugin-mozilla/use-border-radius-tokens": false, "stylelint-plugin-mozilla/use-font-size-tokens": false, "stylelint-plugin-mozilla/use-font-weight-tokens": false, "stylelint-plugin-mozilla/use-space-tokens": false, - "stylelint-plugin-mozilla/use-background-color-tokens": false, + "stylelint-plugin-mozilla/use-text-color-tokens": false, }, }, { @@ -431,10 +433,11 @@ module.exports = { "devtools/client/aboutdebugging/src/**", ], rules: { - "stylelint-plugin-mozilla/use-border-radius-tokens": true, + "stylelint-plugin-mozilla/use-background-color-tokens": false, "stylelint-plugin-mozilla/use-border-color-tokens": false, + "stylelint-plugin-mozilla/use-border-radius-tokens": true, "stylelint-plugin-mozilla/use-space-tokens": false, - "stylelint-plugin-mozilla/use-background-color-tokens": false, + "stylelint-plugin-mozilla/use-text-color-tokens": false, }, }, ], diff --git a/docs/code-quality/lint/linters/stylelint-plugin-mozilla/rules/use-text-color-tokens.rst b/docs/code-quality/lint/linters/stylelint-plugin-mozilla/rules/use-text-color-tokens.rst @@ -0,0 +1,105 @@ +===================== +use-text-color-tokens +===================== + +This rule checks that CSS declarations use text-color design token variables +instead of hard-coded values. This ensures consistent text-color across +the application and makes it easier to maintain design system adoption. + +Examples of incorrect code for this rule: +----------------------------------------- + +.. code-block:: css + + .card { + color: #191919; + } + +.. code-block:: css + + .custom-button { + color: rgba(42 42 42 / 0.15); + } + +.. code-block:: css + + button:hover { + color: rgba(0 0 0 / 0.25); + } + +.. code-block:: css + + :root { + --my-token: blue; + } + + .my-button { + color: var(--my-token, oklch(55% 0.21 15)); + } + +Examples of correct token usage for this rule: +---------------------------------------------- + +.. code-block:: css + + .card { + color: var(--text-color); + } + +.. code-block:: css + + .custom-button { + color: var(--text-color); + } + +.. code-block:: css + + button:hover { + color: --text-color; + } + +.. code-block:: css + + /* You may set a fallback for a token. */ + + .my-button { + color: var(--text-color, oklch(55% 0.21 15)); + } + +.. code-block:: css + + /* Local CSS variables that reference valid text-color tokens are allowed */ + + :root { + --my-token: var(--text-color); + } + + .my-button { + color: var(--my-token, oklch(55% 0.21 15)); + } + +The rule also allows these values non-token values: + +.. code-block:: css + + .inherited-text-color{ + color: inherit; + } + +.. code-block:: css + + .unset-text-color { + color: unset; + } + +.. code-block:: css + + .initial-text-color { + color: initial; + } + +.. code-block:: css + + .current-text-color { + color: currentColor; + } diff --git a/stylelint-rollouts.config.js b/stylelint-rollouts.config.js @@ -1154,4 +1154,243 @@ module.exports = [ "tools/tryselect/selectors/chooser/static/style.css", ], }, + { + // stylelint fixes for this rule will be addressed in Bug 1994016 + name: "rollout-use-text-color-tokens", + rules: { + "stylelint-plugin-mozilla/use-text-color-tokens": null, + }, + files: [ + "browser/branding/aurora/content/aboutDialog.css", + "browser/branding/aurora/stubinstaller/installing_page.css", + "browser/branding/aurora/stubinstaller/profile_cleanup_page.css", + "browser/branding/nightly/content/aboutDialog.css", + "browser/branding/nightly/stubinstaller/installing_page.css", + "browser/branding/nightly/stubinstaller/profile_cleanup_page.css", + "browser/branding/official/content/aboutDialog.css", + "browser/branding/official/stubinstaller/installing_page.css", + "browser/branding/official/stubinstaller/profile_cleanup_page.css", + "browser/branding/unofficial/content/aboutDialog.css", + "browser/branding/unofficial/stubinstaller/installing_page.css", + "browser/branding/unofficial/stubinstaller/profile_cleanup_page.css", + "browser/components/aboutlogins/content/aboutLoginsImportReport.css", + "browser/components/aboutlogins/content/components/import-summary-dialog.css", + "browser/components/aboutlogins/content/components/login-alert.css", + "browser/components/aboutlogins/content/components/login-command-button.css", + "browser/components/aboutlogins/content/components/login-item.css", + "browser/components/aboutwelcome/content-src/aboutwelcome.scss", + "browser/components/asrouter/content-src/components/ASRouterAdmin/ASRouterAdmin.scss", + "browser/components/asrouter/content-src/styles/_feature-callout.scss", + "browser/components/backup/content/password-rules-tooltip.css", + "browser/components/contextualidentity/content/usercontext.css", + "browser/components/enterprisepolicies/content/aboutPolicies.css", + "browser/components/firefoxview/card-container.css", + "browser/components/firefoxview/firefoxview.css", + "browser/components/firefoxview/fxview-empty-state.css", + "browser/components/firefoxview/fxview-tab-row.css", + "browser/components/firefoxview/opentabs-tab-row.css", + "browser/components/firefoxview/view-syncedtabs.css", + "browser/components/genai/content/link-preview-card.css", + "browser/components/ipprotection/content/ipprotection-content.css", + "browser/components/preferences/widgets/nav-notice/nav-notice.css", + "browser/components/profiles/content/edit-profile-card.css", + "browser/components/profiles/content/profile-avatar-selector.css", + "browser/components/profiles/content/profiles-theme-card.css", + "browser/components/protections/content/protections.css", + "browser/components/screenshots/overlay/overlay.css", + "browser/components/screenshots/screenshots-buttons.css", + "browser/components/search/content/contentSearchUI.css", + "browser/components/search/test/browser/telemetry/serp.css", + "browser/components/sidebar/sidebar-customize.css", + "browser/components/sidebar/sidebar-pins-promo.css", + "browser/components/sidebar/sidebar.css", + "browser/components/urlbar/tests/browser/dynamicResult0.css", + "browser/components/urlbar/tests/browser/dynamicResult1.css", + "browser/extensions/formautofill/skin/shared/editDialog-shared.css", + "browser/extensions/newtab/content-src/components/A11yLinkButton/_A11yLinkButton.scss", + "browser/extensions/newtab/content-src/components/Base/_Base.scss", + "browser/extensions/newtab/content-src/components/Card/_Card.scss", + "browser/extensions/newtab/content-src/components/CollapsibleSection/_CollapsibleSection.scss", + "browser/extensions/newtab/content-src/components/CustomizeMenu/_CustomizeMenu.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamAdmin/DiscoveryStreamAdmin.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamBase/_DiscoveryStreamBase.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/AdBanner/_AdBanner.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/CardGrid/_CardGrid.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/CardSections/_CardSections.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/DSContextFooter/_DSContextFooter.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/_DSEmptyState.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/DSMessage/_DSMessage.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/DSTextPromo/_DSTextPromo.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/FeatureHighlight/_DownloadMobilePromoHighlight.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/InterestPicker/_InterestPicker.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/Navigation/_Navigation.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/PersonalizedCard/_PersonalizedCard.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/SectionTitle/_SectionTitle.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/TopicSelection/_TopicSelection.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/TopicsWidget/_TopicsWidget.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/TrendingSearches/_TrendingSearches.scss", + "browser/extensions/newtab/content-src/components/ErrorBoundary/_ErrorBoundary.scss", + "browser/extensions/newtab/content-src/components/ModalOverlay/_ModalOverlay.scss", + "browser/extensions/newtab/content-src/components/Search/_Search.scss", + "browser/extensions/newtab/content-src/components/Sections/_Sections.scss", + "browser/extensions/newtab/content-src/components/TopSites/_TopSites.scss", + "browser/extensions/newtab/content-src/components/WallpaperCategories/_WallpaperCategories.scss", + "browser/extensions/newtab/content-src/components/Weather/_Weather.scss", + "browser/extensions/newtab/content-src/components/Widgets/Lists/_Lists.scss", + "browser/extensions/newtab/content-src/components/Widgets/_Widgets.scss", + "browser/extensions/newtab/content-src/styles/_icons.scss", + "browser/extensions/newtab/content-src/styles/activity-stream.scss", + "browser/extensions/webcompat/about-compat/aboutCompat.css", + "browser/themes/linux/browser.css", + "browser/themes/linux/places/organizer.css", + "browser/themes/osx/browser.css", + "browser/themes/osx/places/organizer.css", + "browser/themes/shared/UITour.css", + "browser/themes/shared/aboutSessionRestore.css", + "browser/themes/shared/addons/unified-extensions.css", + "browser/themes/shared/autocomplete.css", + "browser/themes/shared/blockedSite.css", + "browser/themes/shared/browser-shared.css", + "browser/themes/shared/controlcenter/panel.css", + "browser/themes/shared/customizableui/customizeMode.css", + "browser/themes/shared/customizableui/panelUI-shared.css", + "browser/themes/shared/downloads/downloads.inc.css", + "browser/themes/shared/formautofill-notification.css", + "browser/themes/shared/identity-block/identity-block.css", + "browser/themes/shared/migration/migration-wizard.css", + "browser/themes/shared/pageInfo.css", + "browser/themes/shared/places/sidebar.css", + "browser/themes/shared/places/tree-icons.css", + "browser/themes/shared/preferences/fxaPairDevice.css", + "browser/themes/shared/preferences/preferences.css", + "browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css", + "browser/themes/shared/search/searchbar.css", + "browser/themes/shared/setDesktopBackground.css", + "browser/themes/shared/sidebar.css", + "browser/themes/shared/syncedtabs/sidebar.css", + "browser/themes/shared/tabbrowser/content-area.css", + "browser/themes/shared/tabbrowser/ctrlTab.css", + "browser/themes/shared/tabbrowser/fullscreen-and-pointerlock.css", + "browser/themes/shared/tabbrowser/tabs.css", + "browser/themes/shared/toolbarbuttons.css", + "browser/themes/shared/urlbar-dynamic-results.css", + "browser/themes/shared/urlbar-searchbar.css", + "browser/themes/shared/urlbarView.css", + "browser/themes/shared/webRTC-indicator.css", + "browser/themes/windows/browser.css", + "browser/themes/windows/places/organizer.css", + "browser/tools/mozscreenshots/mozscreenshots/extension/lib/mozscreenshots-style.css", + "dom/crypto/test/test_WebCrypto.css", + "dom/events/test/pointerevents/wpt/pointerevent_styles.css", + "dom/security/test/sri/style1.css", + "dom/security/test/sri/style3.css", + "dom/security/test/sri/style4.css", + "dom/security/test/sri/style5.css", + "dom/security/test/sri/style6.css", + "dom/security/test/sri/style_301.css", + "dom/xml/resources/XMLPrettyPrint.css", + "dom/xml/test/old/books/classic.css", + "dom/xml/test/old/books/common.css", + "dom/xml/test/old/books/list.css", + "dom/xml/test/old/xlink/link.css", + "dom/xml/test/old/xmlbase/xmlbase.css", + "layout/inspector/tests/bug1202095-2.css", + "layout/style/TopLevelImageDocument.css", + "layout/style/res/forms.css", + "layout/style/res/html.css", + "layout/style/res/ua.css", + "layout/style/res/viewsource.css", + "layout/style/test/chrome/bug535806-css.css", + "layout/style/test/chrome/import_useless1.css", + "layout/style/test/chrome/import_useless2.css", + "layout/style/test/file_bug1443344.css", + "layout/style/test/mapped.css", + "layout/style/test/post-redirect-1.css", + "layout/style/test/post-redirect-2.css", + "layout/style/test/post-redirect-3.css", + "netwerk/test/browser/res.css", + "testing/mochitest/static/harness.css", + "testing/mochitest/tests/SimpleTest/test.css", + "testing/mozbase/mozlog/mozlog/formatters/html/style.css", + "testing/talos/talos/tests/scroll/reader.css", + "testing/web-platform/mozilla/tests/fetch/fetchpriority/support/resources/dummy.css", + "toolkit/components/aboutcheckerboard/content/aboutCheckerboard.css", + "toolkit/components/aboutconfig/content/aboutconfig.css", + "toolkit/components/aboutinference/content/aboutInference.css", + "toolkit/components/aboutinference/content/model-files-view.css", + "toolkit/components/aboutmemory/content/aboutMemory.css", + "toolkit/components/aboutprocesses/content/aboutProcesses.css", + "toolkit/components/certviewer/content/components/certificate-section.css", + "toolkit/components/certviewer/content/components/info-item.css", + "toolkit/components/certviewer/content/components/list-item.css", + "toolkit/components/extensions/test/mochitest/file_style_bad.css", + "toolkit/components/extensions/test/mochitest/file_style_good.css", + "toolkit/components/extensions/test/mochitest/file_style_redirect.css", + "toolkit/components/extensions/test/xpcshell/data/file_style_bad.css", + "toolkit/components/extensions/test/xpcshell/data/file_style_good.css", + "toolkit/components/extensions/test/xpcshell/data/file_style_redirect.css", + "toolkit/components/extensions/test/xpcshell/data/file_stylesheet_cache.css", + "toolkit/components/normandy/content/about-studies/about-studies.css", + "toolkit/components/printing/content/printPagination.css", + "toolkit/components/printing/content/printPreview.css", + "toolkit/components/satchel/megalist/content/components/login-form/login-form.css", + "toolkit/components/satchel/megalist/content/components/password-card/password-card.css", + "toolkit/components/satchel/megalist/content/megalist.css", + "toolkit/content/aboutLogging/aboutLogging.css", + "toolkit/content/aboutMozilla.css", + "toolkit/content/aboutwebrtc/aboutWebrtc.css", + "toolkit/content/widgets/infobar.css", + "toolkit/content/widgets/moz-breadcrumb-group/moz-breadcrumb.css", + "toolkit/content/widgets/moz-input-common.css", + "toolkit/content/widgets/moz-input-text/moz-input-text.css", + "toolkit/content/widgets/moz-message-bar/moz-message-bar.css", + "toolkit/content/widgets/moz-page-nav/moz-page-nav-button.css", + "toolkit/content/widgets/moz-promo/moz-promo.css", + "toolkit/content/xul.css", + "toolkit/crashreporter/content/crashes.css", + "toolkit/mozapps/extensions/content/aboutaddons.css", + "toolkit/mozapps/extensions/content/shortcuts.css", + "toolkit/themes/linux/global/autocomplete.css", + "toolkit/themes/linux/global/richlistbox.css", + "toolkit/themes/linux/mozapps/update/updates.css", + "toolkit/themes/mobile/global/aboutMemory.css", + "toolkit/themes/mobile/global/aboutSupport.css", + "toolkit/themes/osx/global/autocomplete.css", + "toolkit/themes/osx/global/button.css", + "toolkit/themes/osx/global/richlistbox.css", + "toolkit/themes/osx/mozapps/handling/handling.css", + "toolkit/themes/osx/mozapps/update/updates.css", + "toolkit/themes/shared/aboutReader.css", + "toolkit/themes/shared/aboutSupport.css", + "toolkit/themes/shared/alert.css", + "toolkit/themes/shared/checkbox.css", + "toolkit/themes/shared/datetimeinputpickers.css", + "toolkit/themes/shared/design-system/tokens-table.css", + "toolkit/themes/shared/dirListing/dirListing.css", + "toolkit/themes/shared/findbar.css", + "toolkit/themes/shared/global-shared.css", + "toolkit/themes/shared/in-content/common-shared.css", + "toolkit/themes/shared/in-content/info-pages.css", + "toolkit/themes/shared/menu.css", + "toolkit/themes/shared/menulist.css", + "toolkit/themes/shared/narrate.css", + "toolkit/themes/shared/pictureinpicture/player.css", + "toolkit/themes/shared/pictureinpicture/texttracks.css", + "toolkit/themes/shared/popup.css", + "toolkit/themes/shared/popupnotification.css", + "toolkit/themes/shared/radio.css", + "toolkit/themes/shared/toolbar.css", + "toolkit/themes/shared/toolbarbutton.css", + "toolkit/themes/shared/tree/tree.css", + "toolkit/themes/windows/global/autocomplete.css", + "toolkit/themes/windows/global/button.css", + "toolkit/themes/windows/global/global.css", + "toolkit/themes/windows/global/richlistbox.css", + "toolkit/themes/windows/global/wizard.css", + "toolkit/themes/windows/mozapps/handling/handling.css", + "toolkit/themes/windows/mozapps/update/updates.css", + "tools/tryselect/selectors/chooser/static/style.css", + ], + }, ]; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/rules/index.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/rules/index.mjs @@ -11,6 +11,7 @@ import useFontSizeTokens from "./use-font-size-tokens.mjs"; import useFontWeightTokens from "./use-font-weight-tokens.mjs"; import useSpaceTokens from "./use-space-tokens.mjs"; import useBackgroundColorTokens from "./use-background-color-tokens.mjs"; +import useTextColorTokens from "./use-text-color-tokens.mjs"; export default { "no-base-design-tokens": noBaseDesignTokens, @@ -20,4 +21,5 @@ export default { "use-font-weight-tokens": useFontWeightTokens, "use-space-tokens": useSpaceTokens, "use-background-color-tokens": useBackgroundColorTokens, + "use-text-color-tokens": useTextColorTokens, }; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/rules/no-base-design-tokens.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/rules/no-base-design-tokens.mjs @@ -2,8 +2,6 @@ * 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 */ - import stylelint from "stylelint"; import { namespace } from "../helpers.mjs"; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/rules/use-border-color-tokens.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/rules/use-border-color-tokens.mjs @@ -1,7 +1,6 @@ /* 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 */ import stylelint from "stylelint"; import { diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/rules/use-text-color-tokens.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/rules/use-text-color-tokens.mjs @@ -0,0 +1,88 @@ +/* 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 stylelint from "stylelint"; +import { + namespace, + createTokenNamesArray, + isValidTokenUsage, + usesRawColors, + createAllowList, + getLocalCustomProperties, +} from "../helpers.mjs"; + +const { + utils: { report, ruleMessages, validateOptions }, +} = stylelint; + +// Name our rule, set the error message, and link to meta +const ruleName = namespace("use-text-color-tokens"); + +const messages = ruleMessages(ruleName, { + rejected: value => `${value} should use a text-color design token.`, +}); + +const meta = { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/stylelint-plugin-mozilla/rules/use-text-color-tokens.html", + fixable: false, +}; + +const INCLUDE_CATEGORIES = ["text-color"]; + +const tokenCSS = createTokenNamesArray(INCLUDE_CATEGORIES); + +// Allowed text-color values in CSS +const ALLOW_LIST = createAllowList(["currentColor"]); + +const CSS_PROPERTIES = ["color"]; + +const ruleFunction = primaryOption => { + return (root, result) => { + const validOptions = validateOptions(result, ruleName, { + actual: primaryOption, + possible: [true], + }); + + if (!validOptions) { + return; + } + + // The first time through gathers our custom properties + const cssCustomProperties = getLocalCustomProperties(root); + + // And then we validate our properties + root.walkDecls(declarations => { + // If the property is not in our list to check, skip it + if (!CSS_PROPERTIES.includes(declarations.prop)) { + return; + } + + // Otherwise, see if we are using the tokens correctly + if ( + isValidTokenUsage( + declarations.value, + tokenCSS, + cssCustomProperties, + ALLOW_LIST + ) && + !usesRawColors(declarations.value) + ) { + return; + } + + report({ + message: messages.rejected(declarations.value), + node: declarations, + result, + ruleName, + }); + }); + }; +}; + +ruleFunction.ruleName = ruleName; +ruleFunction.messages = messages; +ruleFunction.meta = meta; + +export default ruleFunction; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/tests/use-text-color-tokens.tests.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/tests/use-text-color-tokens.tests.mjs @@ -0,0 +1,108 @@ +/** + * 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/PL/2.0/. + */ + +// Bug 1948378: remove this exception when the eslint import plugin fully +// supports exports in package.json files +// eslint-disable-next-line import/no-unresolved +import { testRule } from "stylelint-test-rule-node"; +import stylelint from "stylelint"; +import useTextColorTokens from "../rules/use-text-color-tokens.mjs"; + +let plugin = stylelint.createPlugin( + useTextColorTokens.ruleName, + useTextColorTokens +); +let { + ruleName, + rule: { messages }, +} = plugin; + +testRule({ + plugins: [plugin], + ruleName, + config: true, + fix: false, + accept: [ + { + code: ".a { color: var(--text-color); }", + description: "Using text color token for color is valid.", + }, + { + code: ".a { color: var(--text-color, #000); }", + description: + "Using text color token with fallback value for color is valid.", + }, + { + code: ` + :root { --local-color: var(--text-color); } + .a { color: var(--local-color); } + `, + description: + "Using locally defined variable that falls back to text color token for color is valid.", + }, + { + code: ".a { color: inherit; }", + description: "Using keyword for color is valid.", + }, + { + code: ".a { color: initial; }", + description: "Using keyword for color is valid.", + }, + { + code: ".a { color: revert; }", + description: "Using keyword for color is valid.", + }, + { + code: ".a { color: revert-layer; }", + description: "Using keyword for color is valid.", + }, + { + code: ".a { color: unset; }", + description: "Using keyword for color is valid.", + }, + { + code: ".a { color: currentColor; }", + description: "Using currentColor for color is valid.", + }, + ], + reject: [ + { + code: ".a { color: #000; }", + message: messages.rejected("#000"), + description: "#000 should use a text-color design token.", + }, + { + code: ".a { color: rgba(42 42 42 / 0.15); }", + message: messages.rejected("rgba(42 42 42 / 0.15)"), + description: + "rgba(42 42 42 / 0.15) should use a text-color design token.", + }, + { + code: ".a { color: oklch(69% 0.19 15); }", + message: messages.rejected("oklch(69% 0.19 15)"), + description: "oklch(69% 0.19 15) should use a text-color design token.", + }, + { + code: ".a { color: AccentColorText; }", + message: messages.rejected("AccentColorText"), + description: "AccentColorText should use a text-color design token.", + }, + { + code: ".a { color: var(--random-color, #000); }", + message: messages.rejected("var(--random-color, #000)"), + description: + "var(--random-color, #000) should use a text-color design token.", + }, + { + code: ` + :root { --custom-token: #666; } + .a { color: var(--custom-token); } + `, + message: messages.rejected("var(--custom-token)"), + description: "var(--custom-token) should use a text-color design token.", + }, + ], +});