Skip to content

Commit bedcb4d

Browse files
mirkaciampo
andauthored
ESLint: Add no-ds-tokens rule (#75872)
* Add no-ds-tokens ESLint rule * Enable no-ds-tokens rule for packages/components * Fix regex to also match tokens at start of string * Add changelog * Add comment to eslintrc * Add word-boundary valid test case Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: ciampo <mciampini@git.wordpress.org>
1 parent e22c975 commit bedcb4d

File tree

5 files changed

+159
-0
lines changed

5 files changed

+159
-0
lines changed

.eslintrc.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,16 @@ module.exports = {
436436
plugins: [ 'ssr-friendly' ],
437437
extends: [ 'plugin:ssr-friendly/recommended' ],
438438
},
439+
{
440+
files: [ 'packages/components/src/**' ],
441+
excludedFiles: [ 'packages/components/src/**/@(test|stories)/**' ],
442+
rules: {
443+
// Disallow usage of Design System token CSS custom properties (`--wpds-*`)
444+
// because the fallback injection in the build process is not compatible with Emotion files.
445+
// Can be removed when there are no more Emotion files in the package.
446+
'@wordpress/no-ds-tokens': 'error',
447+
},
448+
},
439449
{
440450
files: [
441451
'packages/block-editor/src/**',

packages/eslint-plugin/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### New Features
6+
7+
- Added [`no-ds-tokens`](https://github.com/WordPress/gutenberg/blob/HEAD/packages/eslint-plugin/docs/rules/no-ds-tokens.md) rule to disallow usage of Design System token CSS custom properties (`--wpds-*`).
8+
59
## 24.2.0 (2026-02-18)
610

711
## 24.1.0 (2026-01-29)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Disallow usage of Design System tokens (no-ds-tokens)
2+
3+
Disallows any usage of Design System token CSS custom properties (beginning with `--wpds-`) in string literals and template literals.
4+
5+
This is useful in contexts where Design System tokens should not be referenced directly. It is not included in any preset and must be explicitly enabled.
6+
7+
## Rule details
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```js
12+
const style = 'color: var(--wpds-color-fg-content-neutral)';
13+
```
14+
15+
```js
16+
const style = `border: 1px solid var(--wpds-border-color)`;
17+
```
18+
19+
```jsx
20+
<div style={ { color: 'var(--wpds-color-fg-content-neutral)' } } />
21+
```
22+
23+
Examples of **correct** code for this rule:
24+
25+
```js
26+
const style = 'color: var(--my-custom-prop)';
27+
```
28+
29+
```js
30+
const style = `border: 1px solid var(--other-prefix-token)`;
31+
```
32+
33+
```jsx
34+
<div style={ { color: 'blue' } } />
35+
```
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { RuleTester } from 'eslint';
2+
import rule from '../no-ds-tokens';
3+
4+
const ruleTester = new RuleTester( {
5+
parserOptions: {
6+
ecmaVersion: 6,
7+
ecmaFeatures: {
8+
jsx: true,
9+
},
10+
},
11+
} );
12+
13+
ruleTester.run( 'no-ds-tokens', rule, {
14+
valid: [
15+
{
16+
code: `const style = 'color: var(--my-custom-prop)';`,
17+
},
18+
{
19+
code: `const style = 'color: blue';`,
20+
},
21+
{
22+
code: 'const style = `border: 1px solid var(--other-prefix-token)`;',
23+
},
24+
{
25+
code: `const name = 'something--wpds-color';`,
26+
},
27+
{
28+
code: `<div style={ { color: 'var(--my-custom-prop)' } } />`,
29+
},
30+
],
31+
invalid: [
32+
{
33+
code: `const style = 'color: var(--wpds-color-fg-content-neutral)';`,
34+
errors: [
35+
{
36+
messageId: 'disallowed',
37+
},
38+
],
39+
},
40+
{
41+
code: 'const style = `color: var(--wpds-color-fg-content-neutral)`;',
42+
errors: [
43+
{
44+
messageId: 'disallowed',
45+
},
46+
],
47+
},
48+
{
49+
code: `<div style={ { color: 'var(--wpds-color-fg-content-neutral)' } } />`,
50+
errors: [
51+
{
52+
messageId: 'disallowed',
53+
},
54+
],
55+
},
56+
{
57+
code: 'const style = `border: 1px solid var(--wpds-border-color, var(--wpds-border-fallback))`;',
58+
errors: [
59+
{
60+
messageId: 'disallowed',
61+
},
62+
],
63+
},
64+
{
65+
code: `const token = '--wpds-color-fg';`,
66+
errors: [
67+
{
68+
messageId: 'disallowed',
69+
},
70+
],
71+
},
72+
{
73+
code: 'const style = `--wpds-color-fg: red`;',
74+
errors: [
75+
{
76+
messageId: 'disallowed',
77+
},
78+
],
79+
},
80+
],
81+
} );
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const DS_TOKEN_PREFIX = 'wpds-';
2+
3+
const wpdsTokensRegex = new RegExp( `(?:^|[^\\w])--${ DS_TOKEN_PREFIX }`, 'i' );
4+
5+
module.exports = /** @type {import('eslint').Rule.RuleModule} */ ( {
6+
meta: {
7+
type: 'problem',
8+
docs: {
9+
description: 'Disallow any usage of --wpds-* CSS custom properties',
10+
},
11+
schema: [],
12+
messages: {
13+
disallowed:
14+
'Design System tokens (--wpds-*) should not be used in this context.',
15+
},
16+
},
17+
create( context ) {
18+
const selector = `:matches(Literal[value=${ wpdsTokensRegex }], TemplateLiteral TemplateElement[value.raw=${ wpdsTokensRegex }])`;
19+
return {
20+
/** @param {import('estree').Literal | import('estree').TemplateElement} node */
21+
[ selector ]( node ) {
22+
context.report( {
23+
node,
24+
messageId: 'disallowed',
25+
} );
26+
},
27+
};
28+
},
29+
} );

0 commit comments

Comments
 (0)