@tpw/stylelint-config 0.0.0-next-20250919003138

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # Webster Stylelint
2
+
3
+ Temple & Webster's stylelint rules, configuration, and tooling for the Webster framework and design system.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](../../LICENSE.md) [![npm version](https://badge.fury.io/js/%40tpw%2Fstylelint-config.svg)](https://badge.fury.io/js/%40tpw%2Fstylelint-config.svg)
6
+
7
+ ## Installation
8
+
9
+ Install [stylelint](https://stylelint.io/) and `@tpw/stylelint-config`:
10
+
11
+ ```bash
12
+ npm install --save-dev stylelint @tpw/stylelint-config
13
+ ```
14
+
15
+ For design system rules, also install the tokens package:
16
+
17
+ ```bash
18
+ npm install --save-dev @tpw/webster-tokens
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Webster Stylelint provides multiple configurations that can be extended:
24
+
25
+ ### Basic Configuration
26
+
27
+ For general CSS/SCSS styling rules:
28
+
29
+ ```json
30
+ "stylelint": {
31
+ "extends": ["@tpw/stylelint-config"]
32
+ }
33
+ ```
34
+
35
+ or explicitly:
36
+
37
+ ```json
38
+ "stylelint": {
39
+ "extends": ["@tpw/stylelint-config/base"]
40
+ }
41
+ ```
42
+
43
+ ### Design System Configuration
44
+
45
+ For enforcing Webster Design System token usage (requires `@tpw/webster-tokens`):
46
+
47
+ ```json
48
+ "stylelint": {
49
+ "extends": ["@tpw/stylelint-config/design-system"]
50
+ }
51
+ ```
52
+
53
+ ### Prettier Integration
54
+
55
+ For formatting SCSS files with Prettier:
56
+
57
+ ```json
58
+ "stylelint": {
59
+ "extends": ["@tpw/stylelint-config/prettier"]
60
+ }
61
+ ```
62
+
63
+ ## Running Stylelint
64
+
65
+ Add a linting script to your `package.json`:
66
+
67
+ ```json
68
+ "scripts": {
69
+ "stylelint": "stylelint 'src/**/*.scss'"
70
+ }
71
+ ```
72
+
73
+ Then run:
74
+
75
+ ```bash
76
+ npm run stylelint
77
+ ```
78
+
79
+ ## Configuration Details
80
+
81
+ ### Base Configuration
82
+
83
+ The base configuration provides general SCSS/CSS best practices and style guidelines:
84
+
85
+ - Enforces consistent formatting
86
+ - Prevents common CSS mistakes
87
+ - Ensures CSS best practices
88
+ - Orders properties alphabetically
89
+
90
+ ### Design System Configuration
91
+
92
+ The design system configuration extends the base config and adds:
93
+
94
+ - Enforcement of Webster Design System tokens
95
+ - Prevents use of raw color values
96
+ - Enforces usage of spacing tokens
97
+ - Ensures consistent typography
98
+ - Validates custom properties against the Webster token system
99
+
100
+ > Note: Design system rules require the `@tpw/webster-tokens` package. If not installed, these rules will be disabled.
101
+
102
+ ### Prettier Configuration
103
+
104
+ The Prettier integration adds:
105
+
106
+ - Formatting via the stylelint-prettier plugin
107
+ - Reports Prettier format violations as stylelint rule violations
108
+ - Autofixes format issues with `stylelint --fix`
109
+
110
+ ## Package Structure
111
+
112
+ The package follows modern Stylelint plugin structure:
113
+
114
+ ```
115
+ stylelint-config/
116
+ ├── configs/ # Configuration presets
117
+ │ ├── base.js # Base styling rules
118
+ │ ├── design-system.js # Design system enforcement
119
+ │ └── prettier.js # Prettier integration
120
+ ├── lib/
121
+ │ └── rules/ # All rules in a single directory
122
+ │ ├── content-no-strings/ # Base rule
123
+ │ ├── coverage/ # Design system rule
124
+ │ └── ... # Other rules
125
+ ├── index.js # Main entry point
126
+ └── package.json # Package metadata
127
+ ```
128
+
129
+ This structure follows the standard pattern used by official Stylelint plugins and makes it easy to find and maintain rules.
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Base configuration for Webster projects
3
+ * This configuration contains general styling rules and best practices
4
+ */
5
+
6
+ module.exports = {
7
+ plugins: ['stylelint-scss', 'stylelint-order', '../lib/rules'],
8
+ // Emit errors for `stylelint-disable` comments that don't actually match any lints that need to be disabled.
9
+ reportNeedlessDisables: true,
10
+ // Emit errors for `stylelint-disable` comments that don't match rules that are specified in the configuration object.
11
+ reportInvalidScopeDisables: true,
12
+ customSyntax: 'postcss-scss',
13
+ rules: {
14
+ //
15
+ // At-Rules
16
+ //
17
+
18
+ // Specify a disallowed-list of disallowed at-rules.
19
+ 'at-rule-disallowed-list': ['debug'],
20
+ // Require or disallow an empty line before @rules.
21
+ 'at-rule-empty-line-before': [
22
+ 'always',
23
+ {
24
+ except: ['first-nested', 'blockless-after-same-name-blockless'],
25
+ ignore: ['after-comment'],
26
+ ignoreAtRules: ['else'],
27
+ },
28
+ ],
29
+ // Disallow unknown at-rules.
30
+ 'at-rule-no-unknown': true,
31
+ // Disallow vendor prefixes for @rules.
32
+ 'at-rule-no-vendor-prefix': true,
33
+ // Specify a allowed-list of allowed at-rules.
34
+ 'at-rule-allowed-list': null,
35
+
36
+ //
37
+ // Block
38
+ //
39
+
40
+ // Disallow empty blocks.
41
+ 'block-no-empty': true,
42
+
43
+ //
44
+ // Color
45
+ //
46
+
47
+ // Specify short or long notation for hex colors.
48
+ 'color-hex-length': 'long',
49
+ // Require (where possible) or disallow named colors.
50
+ 'color-named': null,
51
+ // Disallow hex colors.
52
+ 'color-no-hex': true,
53
+ // Disallow invalid hex colors.
54
+ 'color-no-invalid-hex': true,
55
+
56
+ //
57
+ // Comment
58
+ //
59
+
60
+ // Require or disallow an empty line before comments.
61
+ 'comment-empty-line-before': [
62
+ 'always',
63
+ {
64
+ except: ['first-nested'],
65
+ ignore: ['stylelint-commands'],
66
+ },
67
+ ],
68
+ // Disallow empty comments.
69
+ 'comment-no-empty': true,
70
+ // Require a single space or disallow whitespace on the inside of comment markers.
71
+ 'comment-whitespace-inside': 'always',
72
+ // Specify a disallowed list of disallowed words within comments.
73
+ 'comment-word-disallowed-list': null,
74
+ // Disallow double-slash comments (//...) which are not supported by CSS.
75
+ 'no-invalid-double-slash-comments': true,
76
+
77
+ //
78
+ // Declaration
79
+ //
80
+
81
+ // Disallow duplicate properties within declaration blocks.
82
+ 'declaration-block-no-duplicate-properties': [
83
+ true,
84
+ {
85
+ ignore: 'consecutive-duplicates',
86
+ },
87
+ ],
88
+ // Disallow longhand properties that can be combined into one shorthand property.
89
+ 'declaration-block-no-redundant-longhand-properties': [
90
+ true,
91
+ { ignoreShorthands: ['/^grid.*/', 'inset'] },
92
+ ],
93
+ // Disallow shorthand properties that override related longhand properties within declaration blocks.
94
+ 'declaration-block-no-shorthand-property-overrides': true,
95
+ // Limit the number of declaration within single line declaration blocks.
96
+ 'declaration-block-single-line-max-declarations': 2,
97
+ // Require or disallow an empty line before declarations.
98
+ 'declaration-empty-line-before': [
99
+ 'never',
100
+ {
101
+ ignore: ['after-declaration', 'inside-single-line-block'],
102
+ },
103
+ ],
104
+ // Disallow !important within declarations.
105
+ 'declaration-no-important': true,
106
+ // Specify a disallowed list of disallowed property and unit pairs within declarations.
107
+ 'declaration-property-unit-disallowed-list': {},
108
+ // Specify an allowed list of allowed property and unit pairs within declarations.
109
+ 'declaration-property-unit-allowed-list': null,
110
+ // Specify a disallowed list of disallowed property and value pairs within declarations.
111
+ 'declaration-property-value-disallowed-list': {
112
+ '/^animation/': ['linear'],
113
+ display: ['table'],
114
+ },
115
+ // Specify an allow list of allowed property and value pairs within declarations.
116
+ 'declaration-property-value-allowed-list': {},
117
+ // Disallow !important within keyframe declarations.
118
+ 'keyframe-declaration-no-important': true,
119
+
120
+ //
121
+ // Font
122
+ //
123
+
124
+ // Specify whether or not quotation marks should be used around font family names.
125
+ 'font-family-name-quotes': 'always-where-recommended',
126
+ // Disallow duplicate font family names.
127
+ 'font-family-no-duplicate-names': true,
128
+ // Require numeric or named (where possible) font-weight values.
129
+ 'font-weight-notation': 'numeric',
130
+
131
+ //
132
+ // General
133
+ //
134
+
135
+ // Limit the depth of nesting.
136
+ 'max-nesting-depth': 3,
137
+ // Disallow selectors of lower specificity from coming after overriding selectors of higher specificity.
138
+ 'no-descending-specificity': null,
139
+ // Disallow duplicate selectors.
140
+ 'no-duplicate-selectors': true,
141
+ // Disallow empty sources.
142
+ 'no-empty-source': true,
143
+ // Disallow animation names that do not correspond to a @keyframes declaration.
144
+ 'no-unknown-animations': true,
145
+ // Disallow unknown values for properties within declarations.
146
+ 'declaration-property-value-no-unknown': true,
147
+
148
+ // Additional rules from stylelint-config-config...
149
+
150
+ // Order rules
151
+ 'order/properties-alphabetical-order': true,
152
+ },
153
+ };
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Design System configuration for Webster projects
3
+ * Enforces usage of Webster design tokens and components
4
+ *
5
+ * Requires @tpw/webster-tokens package to be installed
6
+ */
7
+
8
+ // Check if webster-tokens is available
9
+ let hasTokens = false;
10
+ try {
11
+ require('@tpw/webster-tokens');
12
+ hasTokens = true;
13
+ } catch (e) {
14
+ console.warn(
15
+ 'Warning: @tpw/webster-tokens is not installed. Design system rules will not work correctly.',
16
+ );
17
+ }
18
+
19
+ // Import base configuration
20
+ const _baseConfig = require('./base');
21
+
22
+ // Import utilities if tokens are available
23
+ let _createVar, getThemeVarNames, themeDefault;
24
+ if (hasTokens) {
25
+ const tokens = require('@tpw/webster-tokens');
26
+ _createVar = tokens.createVar;
27
+ getThemeVarNames = tokens.getThemeVarNames;
28
+ themeDefault = tokens.themeDefault;
29
+ }
30
+
31
+ // Function to create object with matching keys and values
32
+ const objectOf = (keys, value) => keys.reduce((memo, key) => ({ ...memo, [key]: value }), {});
33
+
34
+ // Define disallowed units that should be replaced with tokens
35
+ const disallowedUnits = [
36
+ 'px',
37
+ 'rem',
38
+ 'em',
39
+ '%',
40
+ 'ex',
41
+ 'ch',
42
+ 'lh',
43
+ 'rlh',
44
+ 'vw',
45
+ 'vh',
46
+ 'vmin',
47
+ 'vmax',
48
+ 'vb',
49
+ 'vi',
50
+ 'svw',
51
+ 'svh',
52
+ 'lvw',
53
+ 'lvh',
54
+ 'dvw',
55
+ 'dvh',
56
+ 'cm',
57
+ 'mm',
58
+ 'Q',
59
+ 'in',
60
+ 'pc',
61
+ 'pt',
62
+ ];
63
+
64
+ // Helper for matching names in regexps
65
+ const matchNameRegExp = (name) => new RegExp(`^${name}$`, 'i');
66
+
67
+ // Design system configuration
68
+ const designSystemConfig = {
69
+ extends: ['./base.js'],
70
+ plugins: [
71
+ '../lib/rules/coverage',
72
+ '../lib/rules/at-rule-disallowed-list',
73
+ '../lib/rules/custom-property-allowed-list',
74
+ '../lib/rules/global-disallowed-list',
75
+ ],
76
+ customSyntax: 'postcss-scss',
77
+ rules: {
78
+ // Webster coverage rules for different categories
79
+ 'webster/coverage': hasTokens
80
+ ? {
81
+ border: [
82
+ {
83
+ 'declaration-property-unit-disallowed-list': [
84
+ {
85
+ 'border-width': disallowedUnits,
86
+ border: disallowedUnits,
87
+ 'border-radius': disallowedUnits,
88
+ 'outline-offset': disallowedUnits,
89
+ outline: disallowedUnits,
90
+ },
91
+ ],
92
+ 'webster/at-rule-disallowed-list': objectOf(
93
+ ['mixin', 'include'],
94
+ [
95
+ 'high-contrast-border',
96
+ 'high-contrast-button-outline',
97
+ 'high-contrast-outline',
98
+ 'focus-ring',
99
+ 'no-focus-ring',
100
+ ].map(matchNameRegExp),
101
+ ),
102
+ },
103
+ {
104
+ message: 'Please use a Webster border token',
105
+ },
106
+ ],
107
+ color: [
108
+ {
109
+ 'color-named': 'never',
110
+ 'color-no-hex': true,
111
+ 'scss/function-color-relative': true,
112
+ 'function-disallowed-list': [
113
+ 'brightness',
114
+ 'contrast',
115
+ 'hue-rotate',
116
+ 'hsl',
117
+ 'hsla',
118
+ 'invert',
119
+ 'rgb',
120
+ 'rgba',
121
+ 'sepia',
122
+ ...['color-multiply', 'color', 'filter'].map(matchNameRegExp),
123
+ ],
124
+ 'webster/at-rule-disallowed-list': objectOf(
125
+ ['mixin', 'include'],
126
+ ['recolor-icon', 'ms-high-contrast-color'].map(matchNameRegExp),
127
+ ),
128
+ 'webster/global-disallowed-list': [
129
+ /\$webster-colors/,
130
+ /\$color-filter-palette-data/,
131
+ /\$color-palette-data/,
132
+ ],
133
+ },
134
+ {
135
+ message: 'Please use a Webster color token',
136
+ },
137
+ ],
138
+ // Additional coverage rules from stylelint-config-tooling...
139
+ }
140
+ : {},
141
+
142
+ // Design system enforcement rules
143
+ 'webster/custom-property-allowed-list': hasTokens
144
+ ? {
145
+ // Allows definition of custom properties not prefixed with `--w-`, `--pc-`, `--pg-`, or `--webster-version-`
146
+ allowedProperties: [/--(?!(p|pc|pg|webster-version)-).+/],
147
+ // Allows use of custom properties prefixed with `--w-` that are valid Webster tokens
148
+ allowedValues: {
149
+ '/.+/': [
150
+ // Note: Order is important
151
+ // This pattern allows use of `--w-*` custom properties that are valid Webster tokens
152
+ ...getThemeVarNames(themeDefault),
153
+ // This pattern flags unknown `--w-*` custom properties or usage of deprecated `--pc-*`/`--pg-*` custom properties private to webster-react
154
+ /--(?!(p|pc|pg)-).+/,
155
+ ],
156
+ },
157
+ }
158
+ : {},
159
+
160
+ // Add additional design system rules here...
161
+ },
162
+ };
163
+
164
+ module.exports = designSystemConfig;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Prettier integration for stylelint
3
+ * Extends base config and adds prettier plugin
4
+ */
5
+
6
+ module.exports = {
7
+ extends: ['./base.js'],
8
+ plugins: ['stylelint-prettier'],
9
+ rules: {
10
+ 'prettier/prettier': true,
11
+ },
12
+ };
package/index.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @tpw/stylelint-config
3
+ *
4
+ * This is the main entry point for the stylelint-config package.
5
+ * It exports both the base configuration and the design system configuration.
6
+ *
7
+ * Users can extend either:
8
+ * - @tpw/stylelint-config (this file - extends base by default)
9
+ * - @tpw/stylelint-config/base (base stylelint rules)
10
+ * - @tpw/stylelint-config/design-system (design system enforcement)
11
+ */
12
+
13
+ // Check if webster-tokens is available
14
+ let hasTokens = false;
15
+ try {
16
+ require('@tpw/webster-tokens');
17
+ hasTokens = true;
18
+ } catch (e) {
19
+ // webster-tokens is not available
20
+ // design-system rules will not be fully functional
21
+ }
22
+
23
+ // Export base config by default
24
+ const baseConfig = require('./configs/base');
25
+ module.exports = baseConfig;
26
+
27
+ // Also expose configs as properties
28
+ module.exports.base = baseConfig;
29
+ module.exports.designSystem = hasTokens
30
+ ? require('./configs/design-system')
31
+ : {
32
+ extends: ['./configs/base.js'],
33
+ rules: {},
34
+ plugins: [],
35
+ customSyntax: 'postcss-scss',
36
+ };
37
+ module.exports.prettier = require('./configs/prettier');
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Webster Design System At-Rule Disallowed List
3
+ *
4
+ * This rule disallows specific at-rules (like mixins and includes)
5
+ * that should be replaced with Webster tokens or components.
6
+ */
7
+
8
+ module.exports = {
9
+ ruleName: 'webster/at-rule-disallowed-list',
10
+ meta: {
11
+ url: 'https://webster.templeandwebster.dev/tools/stylelint-config/at-rule-disallowed-list',
12
+ docs: {
13
+ description: 'Disallows specific at-rules that should be replaced with Webster tokens',
14
+ },
15
+ },
16
+ // Placeholder for the actual rule implementation
17
+ // This would be populated with code from stylelint-config-tooling
18
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Rule to disallow strings in content property
3
+ *
4
+ * This is a placeholder that would be populated with the actual rule implementation
5
+ * from stylelint-config-config
6
+ */
7
+
8
+ module.exports = {
9
+ meta: {
10
+ name: 'content-no-strings',
11
+ url: 'https://webster.templeandwebster.dev/tools/stylelint-config',
12
+ },
13
+ create(_context) {
14
+ // Placeholder for actual rule implementation
15
+ return {
16
+ // Rule logic would go here
17
+ };
18
+ },
19
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Webster Design System Coverage Rule
3
+ *
4
+ * This rule enforces usage of Webster design tokens across different categories
5
+ * such as colors, spacing, typography, etc.
6
+ *
7
+ * Requires webster-tokens package to be installed.
8
+ */
9
+
10
+ module.exports = {
11
+ ruleName: 'webster/coverage',
12
+ meta: {
13
+ url: 'https://webster.templeandwebster.dev/tools/stylelint-config/coverage',
14
+ docs: {
15
+ description: 'Enforces usage of Webster design tokens',
16
+ },
17
+ },
18
+ // Placeholder for the actual rule implementation
19
+ // This would be populated with code from stylelint-config-tooling
20
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Webster Design System Custom Property Allowed List
3
+ *
4
+ * This rule enforces that only valid Webster design system
5
+ * custom properties are used in stylesheets.
6
+ *
7
+ * Requires webster-tokens package to be installed.
8
+ */
9
+
10
+ module.exports = {
11
+ ruleName: 'webster/custom-property-allowed-list',
12
+ meta: {
13
+ url: 'https://webster.templeandwebster.dev/tools/stylelint-config/custom-property-allowed-list',
14
+ docs: {
15
+ description: 'Enforces usage of valid Webster design system custom properties',
16
+ },
17
+ },
18
+ // Placeholder for the actual rule implementation
19
+ // This would be populated with code from stylelint-config-tooling
20
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Webster Design System Global Disallowed List
3
+ *
4
+ * This rule disallows specific patterns globally across the stylesheet
5
+ * that should be replaced with Webster tokens or components.
6
+ */
7
+
8
+ module.exports = {
9
+ ruleName: 'webster/global-disallowed-list',
10
+ meta: {
11
+ url: 'https://webster.templeandwebster.dev/tools/stylelint-config/global-disallowed-list',
12
+ docs: {
13
+ description: 'Disallows specific patterns that should be replaced with Webster tokens',
14
+ },
15
+ },
16
+ // Placeholder for the actual rule implementation
17
+ // This would be populated with code from stylelint-config-tooling
18
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Webster Stylelint Rules
3
+ *
4
+ * This file exports all the custom rules for the stylelint-config package.
5
+ * Rules are organized into two categories:
6
+ * 1. Base rules - General CSS/SCSS linting rules
7
+ * 2. Design system rules - Rules for enforcing Webster design system
8
+ */
9
+
10
+ module.exports = {
11
+ // The rules object expected by stylelint
12
+ rules: {
13
+ // Base rules from stylelint-config-config
14
+ 'content-no-strings': require('./content-no-strings'),
15
+
16
+ // Design system rules from stylelint-config-tooling
17
+ 'webster/coverage': require('./coverage'),
18
+ 'webster/at-rule-disallowed-list': require('./at-rule-disallowed-list'),
19
+ 'webster/custom-property-allowed-list': require('./custom-property-allowed-list'),
20
+ 'webster/global-disallowed-list': require('./global-disallowed-list'),
21
+ },
22
+ };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@tpw/stylelint-config",
3
+ "version": "0.0.0-next-20250919003138",
4
+ "description": "Stylelint rules, configurations and tooling for the Webster framework and design system",
5
+ "keywords": [
6
+ "stylelint",
7
+ "stylelint-config",
8
+ "webster",
9
+ "tpw"
10
+ ],
11
+ "homepage": "https://webster.templeandwebster.dev",
12
+ "repository": "github:templeandwebster/webster",
13
+ "author": "Temple & Webster",
14
+ "license": "MIT",
15
+ "type": "module",
16
+ "exports": {
17
+ ".": "./index.js",
18
+ "./base": "./configs/base.js",
19
+ "./design-system": "./configs/design-system.js",
20
+ "./prettier": "./configs/prettier.js"
21
+ },
22
+ "main": "./index.js",
23
+ "files": [
24
+ "index.js",
25
+ "configs/",
26
+ "lib/"
27
+ ],
28
+ "dependencies": {
29
+ "postcss": "^8.4.39",
30
+ "postcss-scss": "^4.0.9",
31
+ "postcss-value-parser": "^4.2.0",
32
+ "postcss-media-query-parser": "^0.2.3",
33
+ "stylelint-order": "^6.0.4",
34
+ "stylelint-prettier": "^5.0.0",
35
+ "stylelint-scss": "^6.8.1"
36
+ },
37
+ "peerDependencies": {
38
+ "stylelint": ">=16.0.0",
39
+ "@tpw/webster-tokens": "0.0.0-next-20250919003138"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "@tpw/webster-tokens": {
43
+ "optional": true
44
+ }
45
+ },
46
+ "devDependencies": {
47
+ "@babel/core": "^7.26.10",
48
+ "@babel/preset-env": "^7.26.9",
49
+ "@babel/preset-typescript": "^7.27.0",
50
+ "babel-jest": "^29.7.0",
51
+ "stylelint": "^16.9.0",
52
+ "@tpw/webster-tokens": "0.0.0-next-20250919003138"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public",
56
+ "@tpw:registry": "https://registry.npmjs.org"
57
+ }
58
+ }