@master/eslint-plugin-css 0.0.0-site.1793659883.g69c9aebcf628
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 +291 -0
- package/dist/configs/base.d.ts +3 -0
- package/dist/configs/base.js +4 -0
- package/dist/configs/recommended.d.ts +3 -0
- package/dist/configs/recommended.js +12 -0
- package/dist/create-rule.d.ts +5 -0
- package/dist/create-rule.js +4 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +15 -0
- package/dist/internal/src/workspace-directories.js +67 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.js +28 -0
- package/dist/rules/no-conflicting-classes.d.ts +4 -0
- package/dist/rules/no-conflicting-classes.js +39 -0
- package/dist/rules/no-invalid-classes.d.ts +4 -0
- package/dist/rules/no-invalid-classes.js +41 -0
- package/dist/rules/no-unapproved-raw-values.d.ts +8 -0
- package/dist/rules/no-unapproved-raw-values.js +63 -0
- package/dist/rules/prefer-canonical-classes.d.ts +5 -0
- package/dist/rules/prefer-canonical-classes.js +48 -0
- package/dist/rules/prefer-component-classes.d.ts +4 -0
- package/dist/rules/prefer-component-classes.js +45 -0
- package/dist/rules/sort-classes.d.ts +4 -0
- package/dist/rules/sort-classes.js +38 -0
- package/dist/settings-schema.d.ts +4 -0
- package/dist/settings-schema.js +26 -0
- package/dist/settings.d.ts +16 -0
- package/dist/settings.js +7 -0
- package/dist/utils/define-source-visitors.d.ts +13 -0
- package/dist/utils/define-source-visitors.js +51 -0
- package/dist/utils/define-visitors.d.ts +11 -0
- package/dist/utils/define-visitors.js +102 -0
- package/dist/utils/dependency-stamp.d.ts +10 -0
- package/dist/utils/dependency-stamp.js +27 -0
- package/dist/utils/is-same-or-child-path.d.ts +2 -0
- package/dist/utils/is-same-or-child-path.js +7 -0
- package/dist/utils/javascript-literal.d.ts +3 -0
- package/dist/utils/javascript-literal.js +51 -0
- package/dist/utils/master-css.d.ts +3 -0
- package/dist/utils/master-css.js +4 -0
- package/dist/utils/report-lint-diagnostics.d.ts +20 -0
- package/dist/utils/report-lint-diagnostics.js +54 -0
- package/dist/utils/resolve-class-node.d.ts +26 -0
- package/dist/utils/resolve-class-node.js +106 -0
- package/dist/utils/resolve-context.d.ts +15 -0
- package/dist/utils/resolve-context.js +177 -0
- package/dist/utils/source-tooling.d.ts +7 -0
- package/dist/utils/source-tooling.js +40 -0
- package/dist/utils/vue-literal.d.ts +8 -0
- package/dist/utils/vue-literal.js +61 -0
- package/dist/utils/with-context-release.d.ts +3 -0
- package/dist/utils/with-context-release.js +15 -0
- package/dist/utils/with-visit-class-node.d.ts +6 -0
- package/dist/utils/with-visit-class-node.js +50 -0
- package/dist/utils/workspace-cache.d.ts +11 -0
- package/dist/utils/workspace-cache.js +30 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
<br>
|
|
2
|
+
<div align="center">
|
|
3
|
+
|
|
4
|
+
<p align="center">
|
|
5
|
+
<a href="https://css.master.co">
|
|
6
|
+
<picture>
|
|
7
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/33840671/201701649-3bb7d698-abec-4d5f-ac30-ccc4d7bafcd4.svg">
|
|
8
|
+
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/33840671/201703010-77bf2373-9899-40cc-98f5-30cf9b546941.svg">
|
|
9
|
+
<img alt="Master CSS" src="https://user-images.githubusercontent.com/33840671/201703010-77bf2373-9899-40cc-98f5-30cf9b546941.svg" width="100%">
|
|
10
|
+
</picture>
|
|
11
|
+
</a>
|
|
12
|
+
</p>
|
|
13
|
+
<p align="center">An ESLint plugin enforcing a consistent coding style for Master CSS</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a aria-label="GitHub release (latest by date including pre-releases)" href="https://github.com/master-co/css/releases">
|
|
17
|
+
<picture>
|
|
18
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/v/release/master-co/css?include_prereleases&color=212022&label=&style=for-the-badge&logo=github&logoColor=fff">
|
|
19
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/v/release/master-co/css?include_prereleases&color=f6f7f8&label=&style=for-the-badge&logo=github&logoColor=%23000">
|
|
20
|
+
<img alt="NPM Version" src="https://img.shields.io/github/v/release/master-co/css?include_prereleases&color=f6f7f8&label=&style=for-the-badge&logo=github">
|
|
21
|
+
</picture>
|
|
22
|
+
</a>
|
|
23
|
+
<a aria-label="NPM Package" href="https://www.npmjs.com/package/@master/eslint-plugin-css">
|
|
24
|
+
<picture>
|
|
25
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/@master/eslint-plugin-css?color=212022&label=%20&logo=npm&style=for-the-badge">
|
|
26
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/npm/dm/@master/eslint-plugin-css?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
|
|
27
|
+
<img alt="NPM package ( download / month )" src="https://img.shields.io/npm/dm/@master/eslint-plugin-css?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
|
|
28
|
+
</picture>
|
|
29
|
+
</a>
|
|
30
|
+
<a aria-label="Discord Community" href="https://discord.gg/sZNKpAAAw6">
|
|
31
|
+
<picture>
|
|
32
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/discord/917780624314613760?color=212022&label=%20&logo=discord&style=for-the-badge">
|
|
33
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/discord/917780624314613760?color=f6f7f8&label=%20&logo=discord&style=for-the-badge">
|
|
34
|
+
<img alt="Discord online" src="https://img.shields.io/discord/917780624314613760?color=f6f7f8&label=%20&logo=discord&style=for-the-badge">
|
|
35
|
+
</picture>
|
|
36
|
+
</a>
|
|
37
|
+
<a aria-label="Follow @mastercorg" href="https://twitter.com/mastercorg">
|
|
38
|
+
<picture>
|
|
39
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/static/v1?label=%20&message=twitter&color=212022&logo=twitter&style=for-the-badge">
|
|
40
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
|
|
41
|
+
<img alt="Follow @mastercorg" src="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
|
|
42
|
+
</picture>
|
|
43
|
+
</a>
|
|
44
|
+
<a aria-label="Github Actions" href="https://github.com/master-co/css/actions/workflows/ci-release.yml">
|
|
45
|
+
<picture>
|
|
46
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
|
|
47
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
48
|
+
<img alt="Github release actions" src="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
49
|
+
</picture>
|
|
50
|
+
</a>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install -D @master/eslint-config-css
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The config package installs the matching plugin implementation and exposes the
|
|
62
|
+
complete recommended flat config.
|
|
63
|
+
|
|
64
|
+
In Visual Studio Code, install the VS Code ESLint extension to surface these diagnostics and run sort-on-save. The Master CSS extension provides completion, hover, colors, highlighting, directive diagnostics, manifest diagnostics, and directive formatting; it does not duplicate class policy warnings by default.
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
Use ESLint flat configuration:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import { defineConfig } from 'eslint/config'
|
|
72
|
+
import masterCSS from '@master/eslint-config-css'
|
|
73
|
+
import htmlParser from '@angular-eslint/template-parser'
|
|
74
|
+
import tsParser from '@typescript-eslint/parser'
|
|
75
|
+
|
|
76
|
+
export default defineConfig([
|
|
77
|
+
{
|
|
78
|
+
files: ['**/*.html'],
|
|
79
|
+
languageOptions: {
|
|
80
|
+
parser: htmlParser
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
files: ['**/*.{ts,tsx}'],
|
|
85
|
+
languageOptions: {
|
|
86
|
+
parser: tsParser
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
...masterCSS,
|
|
90
|
+
{
|
|
91
|
+
rules: {
|
|
92
|
+
'@master/css/no-invalid-classes': ['error', {
|
|
93
|
+
disallowUnknownClass: true
|
|
94
|
+
}]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
])
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Rules
|
|
101
|
+
|
|
102
|
+
### `@master/css/sort-classes`
|
|
103
|
+
|
|
104
|
+
Sorts Master CSS classes into a consistent and logical order.
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
import { defineConfig } from 'eslint/config'
|
|
108
|
+
|
|
109
|
+
export default defineConfig([
|
|
110
|
+
{
|
|
111
|
+
rules: {
|
|
112
|
+
'@master/css/sort-classes': 'warn'
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `@master/css/no-invalid-classes`
|
|
119
|
+
|
|
120
|
+
Disallows invalid Master CSS classes.
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
import { defineConfig } from 'eslint/config'
|
|
124
|
+
|
|
125
|
+
export default defineConfig([
|
|
126
|
+
{
|
|
127
|
+
rules: {
|
|
128
|
+
'@master/css/no-invalid-classes': 'error'
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
])
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Set `disallowUnknownClass: true` to reject classes that do not match the active manifest:
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
import { defineConfig } from 'eslint/config'
|
|
138
|
+
|
|
139
|
+
export default defineConfig([
|
|
140
|
+
{
|
|
141
|
+
rules: {
|
|
142
|
+
'@master/css/no-invalid-classes': ['error', {
|
|
143
|
+
disallowUnknownClass: true
|
|
144
|
+
}]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
])
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `@master/css/prefer-canonical-classes`
|
|
151
|
+
|
|
152
|
+
Prefers canonical Master CSS class forms, including named token utilities and valid utility recipes. Direct declaration classes retain full native property names and authored condition order.
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
import { defineConfig } from 'eslint/config'
|
|
156
|
+
|
|
157
|
+
export default defineConfig([
|
|
158
|
+
{
|
|
159
|
+
rules: {
|
|
160
|
+
'@master/css/prefer-canonical-classes': 'warn'
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
])
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
For example, condition sorting changes `block@dark@sm` to `block@sm@dark`. Canonical fixes preserve value source and ordering: they do not replace literals with currently equal tokens or convert pixels to rem. Keep paired dimensions explicit (`w-sm h-sm`).
|
|
167
|
+
|
|
168
|
+
Canonicalization applies to class lists in markup and class builders; stylesheet declarations use native CSS.
|
|
169
|
+
|
|
170
|
+
Standalone CSS files are included by default when using `@master/eslint-config-css`:
|
|
171
|
+
|
|
172
|
+
```js
|
|
173
|
+
import { defineConfig } from 'eslint/config'
|
|
174
|
+
import masterCSS from '@master/eslint-config-css'
|
|
175
|
+
|
|
176
|
+
export default defineConfig([
|
|
177
|
+
...masterCSS
|
|
178
|
+
])
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
You can disable specific canonicalization families:
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
import { defineConfig } from 'eslint/config'
|
|
185
|
+
|
|
186
|
+
export default defineConfig([
|
|
187
|
+
{
|
|
188
|
+
rules: {
|
|
189
|
+
'@master/css/prefer-canonical-classes': ['warn', {
|
|
190
|
+
preferStaticUtilities: true,
|
|
191
|
+
preferCompositionUtilities: true,
|
|
192
|
+
preferConditionOrder: true
|
|
193
|
+
}]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
])
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `@master/css/no-conflicting-classes`
|
|
200
|
+
|
|
201
|
+
Disallows classes that emit the same CSS declaration properties for the same variant.
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
import { defineConfig } from 'eslint/config'
|
|
205
|
+
|
|
206
|
+
export default defineConfig([
|
|
207
|
+
{
|
|
208
|
+
rules: {
|
|
209
|
+
'@master/css/no-conflicting-classes': 'warn'
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
])
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
When two classes conflict, the later class is treated as the effective one and the fix removes the earlier class. For partially overlapping spacing, physical inset, radius, and border width/color/style shorthands, the fix preserves the surviving declarations by splitting the earlier class, such as `mx-md ml-lg` to `mr-md ml-lg` or `b-solid bt-dashed` to `br-solid bb-solid bl-solid bt-dashed`.
|
|
216
|
+
|
|
217
|
+
### `@master/css/no-unapproved-raw-values`
|
|
218
|
+
|
|
219
|
+
Disallows raw values in token-backed utilities unless they are explicitly allowed. This rule is opt-in team policy and is not enabled by the recommended config.
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
import { defineConfig } from 'eslint/config'
|
|
223
|
+
|
|
224
|
+
export default defineConfig([
|
|
225
|
+
{
|
|
226
|
+
rules: {
|
|
227
|
+
'@master/css/no-unapproved-raw-values': ['warn', {
|
|
228
|
+
allowProperties: ['width', 'height'],
|
|
229
|
+
allowedPatterns: ['^var\\(', '^calc\\(']
|
|
230
|
+
}]
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
])
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
For example, this rule reports `(font-size:15px)`, `(margin:17px)`, and `(color:#123456)` when those values are not theme tokens. It does not autofix because there may be no safe token replacement.
|
|
237
|
+
|
|
238
|
+
### `@master/css/prefer-component-classes`
|
|
239
|
+
|
|
240
|
+
Reports a class list in which more than `max` classes (default `3`) style other elements through a top-level combinator: `_` descendant, `>` child, `+` or `~` sibling. Past that point the styling belongs in a component class in `@layer components`. This rule is opt-in and is not enabled by the recommended config.
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
import { defineConfig } from 'eslint/config'
|
|
244
|
+
|
|
245
|
+
export default defineConfig([
|
|
246
|
+
{
|
|
247
|
+
rules: {
|
|
248
|
+
'@master/css/prefer-component-classes': ['warn', { max: 3 }]
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
])
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`flex block_h4 hidden_h4 grid_svg flex>li` reports once: four classes reach other elements. States of the element itself (`:hover`), relative selectors inside `:has()` or `:is()`, and conditions such as `@sm` never count. It has no autofix.
|
|
255
|
+
|
|
256
|
+
## Settings
|
|
257
|
+
|
|
258
|
+
Settings live under the `@master/css` settings key:
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
import { defineConfig } from 'eslint/config'
|
|
262
|
+
|
|
263
|
+
export default defineConfig([
|
|
264
|
+
{
|
|
265
|
+
settings: {
|
|
266
|
+
'@master/css': {
|
|
267
|
+
classAttributes: ['class', 'className'],
|
|
268
|
+
classFunctions: ['clsx', 'classList.add'],
|
|
269
|
+
classDeclarations: ['classes'],
|
|
270
|
+
ignoredKeys: ['compoundVariants', 'defaultVariants'],
|
|
271
|
+
manifest
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
])
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
| Setting | Type | Description |
|
|
279
|
+
| --- | --- | --- |
|
|
280
|
+
| `classAttributes` | `string[]` | Element attributes containing class strings. |
|
|
281
|
+
| `classFunctions` | `string[]` | Function names whose arguments should be checked. |
|
|
282
|
+
| `classDeclarations` | `string[]` | Variable/member names whose declarations should be checked. |
|
|
283
|
+
| `ignoredKeys` | `string[]` | Object keys ignored during checking. Defaults include variant metadata keys. |
|
|
284
|
+
| `manifest` | `MasterCSSManifest` | Explicit compiled manifest. By default, ESLint loads the project CSS entry discovered from the current working directory. |
|
|
285
|
+
|
|
286
|
+
## Related docs
|
|
287
|
+
|
|
288
|
+
See the [code linting guide](https://rc.css.master.co/guide/code-linting) for setup guides across frameworks and editors.
|
|
289
|
+
|
|
290
|
+
## Credits
|
|
291
|
+
This plugin is heavily inspired by the awesome [eslint-plugin-tailwindcss](https://github.com/francoismassart/eslint-plugin-tailwindcss). We want to thank for their initial work, which served as the foundation for this project. While significant modifications have been made, the core ideas and concepts from A Plugin have been instrumental in developing this plugin.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import base_default from "./base.js";
|
|
2
|
+
// src/configs/recommended.ts
|
|
3
|
+
var recommended_default = {
|
|
4
|
+
...base_default,
|
|
5
|
+
rules: {
|
|
6
|
+
"@master/css/sort-classes": "warn",
|
|
7
|
+
"@master/css/no-invalid-classes": "error",
|
|
8
|
+
"@master/css/no-conflicting-classes": "warn",
|
|
9
|
+
"@master/css/prefer-canonical-classes": "warn"
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export { recommended_default as default };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
2
|
+
declare const _default: <Options extends readonly unknown[], MessageIds extends string>({ meta, name, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<Options, MessageIds, unknown>>) => ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export { _default as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TSESLint } from "@typescript-eslint/utils";
|
|
2
|
+
import { Linter } from "eslint";
|
|
3
|
+
import settings from "./settings.js";
|
|
4
|
+
declare const masterCSSPlugin: Omit<TSESLint.Linter.Plugin, 'configs'> & {
|
|
5
|
+
configs: {
|
|
6
|
+
base: Linter.Config;
|
|
7
|
+
recommended: Linter.Config[];
|
|
8
|
+
source: Linter.Config;
|
|
9
|
+
};
|
|
10
|
+
settings: typeof settings;
|
|
11
|
+
};
|
|
12
|
+
export { masterCSSPlugin as default, masterCSSPlugin as masterCSS };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import settings from "./settings.js";
|
|
2
|
+
import plugin from "./plugin.js";
|
|
3
|
+
import base_default from "./configs/base.js";
|
|
4
|
+
import recommended_default from "./configs/recommended.js";
|
|
5
|
+
// src/index.ts
|
|
6
|
+
const masterCSSPlugin = {
|
|
7
|
+
...plugin,
|
|
8
|
+
configs: {
|
|
9
|
+
base: base_default,
|
|
10
|
+
recommended: [recommended_default],
|
|
11
|
+
source: recommended_default
|
|
12
|
+
},
|
|
13
|
+
settings
|
|
14
|
+
};
|
|
15
|
+
export { masterCSSPlugin as default, masterCSSPlugin as masterCSS };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
2
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
3
|
+
// ../internal/src/workspace-directories.ts
|
|
4
|
+
const IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
5
|
+
"node_modules",
|
|
6
|
+
"dist",
|
|
7
|
+
"out",
|
|
8
|
+
".master",
|
|
9
|
+
".next",
|
|
10
|
+
".nuxt",
|
|
11
|
+
".svelte-kit"
|
|
12
|
+
]);
|
|
13
|
+
const MASTER_CSS_PACKAGE_NAME = /^@master\/css(?:$|[.-])/;
|
|
14
|
+
const DEPENDENCY_FIELDS = [
|
|
15
|
+
"dependencies",
|
|
16
|
+
"devDependencies",
|
|
17
|
+
"peerDependencies",
|
|
18
|
+
"optionalDependencies"
|
|
19
|
+
];
|
|
20
|
+
function hasMasterCSSDependency(packageJSON) {
|
|
21
|
+
return DEPENDENCY_FIELDS.some((field) => {
|
|
22
|
+
const dependencies = packageJSON[field];
|
|
23
|
+
return dependencies && typeof dependencies === "object" && Object.keys(dependencies).some((dependency) => MASTER_CSS_PACKAGE_NAME.test(dependency));
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function collectPackageDirectoriesSync(directory, directories, onInput) {
|
|
27
|
+
onInput?.(directory);
|
|
28
|
+
try {
|
|
29
|
+
for (const dirent of readdirSync(directory, { withFileTypes: true })) {
|
|
30
|
+
const file = join(directory, dirent.name);
|
|
31
|
+
if (dirent.isDirectory()) {
|
|
32
|
+
if (!IGNORED_DIRECTORIES.has(dirent.name)) collectPackageDirectoriesSync(file, directories, onInput);
|
|
33
|
+
} else if (dirent.isFile()) {
|
|
34
|
+
if (dirent.name.endsWith(".css") || dirent.name === "package.json") onInput?.(file);
|
|
35
|
+
if (dirent.name !== "package.json") continue;
|
|
36
|
+
try {
|
|
37
|
+
if (hasMasterCSSDependency(JSON.parse(readFileSync(file, "utf8")))) directories.add(dirname(file));
|
|
38
|
+
} catch {}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} catch {}
|
|
42
|
+
}
|
|
43
|
+
function isSameOrChildPath(parent, child) {
|
|
44
|
+
const path = relative(parent, child);
|
|
45
|
+
return path === "" || path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute(path);
|
|
46
|
+
}
|
|
47
|
+
function resolveEntryWorkspace(entry, directories) {
|
|
48
|
+
const absoluteEntry = resolve(entry);
|
|
49
|
+
let closest;
|
|
50
|
+
for (const directory of directories) {
|
|
51
|
+
const absoluteDirectory = resolve(directory);
|
|
52
|
+
if (isSameOrChildPath(absoluteDirectory, absoluteEntry) && (!closest || absoluteDirectory.length > closest.length)) closest = absoluteDirectory;
|
|
53
|
+
}
|
|
54
|
+
return closest ?? dirname(absoluteEntry);
|
|
55
|
+
}
|
|
56
|
+
function finalizeWorkspaceDirectories(root, packageDirectories, manifestEntries) {
|
|
57
|
+
const directories = /* @__PURE__ */ new Set([root, ...packageDirectories]);
|
|
58
|
+
for (const entry of manifestEntries) directories.add(resolveEntryWorkspace(entry, packageDirectories));
|
|
59
|
+
return Object.freeze([...directories].sort());
|
|
60
|
+
}
|
|
61
|
+
function discoverBuildWorkspaceDirectoriesSync(rootDirectory, manifestEntries = [], onInput) {
|
|
62
|
+
const root = resolve(rootDirectory);
|
|
63
|
+
const packageDirectories = /* @__PURE__ */ new Set();
|
|
64
|
+
collectPackageDirectoriesSync(root, packageDirectories, onInput);
|
|
65
|
+
return finalizeWorkspaceDirectories(root, packageDirectories, manifestEntries);
|
|
66
|
+
}
|
|
67
|
+
export { discoverBuildWorkspaceDirectoriesSync };
|
package/dist/plugin.d.ts
ADDED
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import no_conflicting_classes_default from "./rules/no-conflicting-classes.js";
|
|
2
|
+
import no_invalid_classes_default from "./rules/no-invalid-classes.js";
|
|
3
|
+
import no_unapproved_raw_values_default from "./rules/no-unapproved-raw-values.js";
|
|
4
|
+
import prefer_canonical_classes_default from "./rules/prefer-canonical-classes.js";
|
|
5
|
+
import prefer_component_classes_default from "./rules/prefer-component-classes.js";
|
|
6
|
+
import sort_classes_default from "./rules/sort-classes.js";
|
|
7
|
+
import { readFileSync } from "fs";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import { dirname, resolve } from "path";
|
|
10
|
+
// src/plugin.ts
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, "..", "package.json"), "utf-8"));
|
|
14
|
+
const plugin = {
|
|
15
|
+
meta: {
|
|
16
|
+
name: pkg.name,
|
|
17
|
+
version: pkg.version
|
|
18
|
+
},
|
|
19
|
+
rules: {
|
|
20
|
+
"no-conflicting-classes": no_conflicting_classes_default,
|
|
21
|
+
"no-invalid-classes": no_invalid_classes_default,
|
|
22
|
+
"no-unapproved-raw-values": no_unapproved_raw_values_default,
|
|
23
|
+
"prefer-canonical-classes": prefer_canonical_classes_default,
|
|
24
|
+
"prefer-component-classes": prefer_component_classes_default,
|
|
25
|
+
"sort-classes": sort_classes_default
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export { plugin as default };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import create_rule_default from "../create-rule.js";
|
|
2
|
+
import defineVisitors from "../utils/define-visitors.js";
|
|
3
|
+
import resolveContext from "../utils/resolve-context.js";
|
|
4
|
+
import reportLintDiagnostics from "../utils/report-lint-diagnostics.js";
|
|
5
|
+
import defineSourceVisitors, { shouldUseSourceVisitors } from "../utils/define-source-visitors.js";
|
|
6
|
+
import withContextRelease from "../utils/with-context-release.js";
|
|
7
|
+
import { createMasterCSSLintDiagnostics } from "@master/css-tooling/lint";
|
|
8
|
+
// src/rules/no-conflicting-classes.ts
|
|
9
|
+
var no_conflicting_classes_default = create_rule_default({
|
|
10
|
+
name: "no-conflicting-classes",
|
|
11
|
+
meta: {
|
|
12
|
+
type: "layout",
|
|
13
|
+
docs: { description: "Disallow conflicting Master CSS classes" },
|
|
14
|
+
messages: {
|
|
15
|
+
collisionClass: "{{message}}",
|
|
16
|
+
partialCollisionClass: "{{message}}"
|
|
17
|
+
},
|
|
18
|
+
fixable: "code",
|
|
19
|
+
schema: []
|
|
20
|
+
},
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
create(context) {
|
|
23
|
+
const { settings, tooling, release } = resolveContext(context);
|
|
24
|
+
if (shouldUseSourceVisitors(context)) return withContextRelease(defineSourceVisitors({
|
|
25
|
+
context,
|
|
26
|
+
tooling,
|
|
27
|
+
ruleId: "no-conflicting-classes"
|
|
28
|
+
}), release);
|
|
29
|
+
return withContextRelease(defineVisitors({
|
|
30
|
+
context,
|
|
31
|
+
settings,
|
|
32
|
+
tooling
|
|
33
|
+
}, (node, resolved) => {
|
|
34
|
+
const diagnostics = createMasterCSSLintDiagnostics(tooling.analyzeLintClassList(resolved.analysisText ?? resolved.raw, resolved.classValues).diagnostics.filter(({ ruleId }) => ruleId === "no-conflicting-classes"));
|
|
35
|
+
reportLintDiagnostics(context, node, resolved, diagnostics);
|
|
36
|
+
}), release);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
export { no_conflicting_classes_default as default };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import create_rule_default from "../create-rule.js";
|
|
2
|
+
import defineVisitors from "../utils/define-visitors.js";
|
|
3
|
+
import resolveContext from "../utils/resolve-context.js";
|
|
4
|
+
import reportLintDiagnostics from "../utils/report-lint-diagnostics.js";
|
|
5
|
+
import defineSourceVisitors, { shouldUseSourceVisitors } from "../utils/define-source-visitors.js";
|
|
6
|
+
import withContextRelease from "../utils/with-context-release.js";
|
|
7
|
+
import { noInvalidClassesOptionsSchema } from "../settings-schema.js";
|
|
8
|
+
import { createMasterCSSLintDiagnostics } from "@master/css-tooling/lint";
|
|
9
|
+
// src/rules/no-invalid-classes.ts
|
|
10
|
+
var no_invalid_classes_default = create_rule_default({
|
|
11
|
+
name: "no-invalid-classes",
|
|
12
|
+
meta: {
|
|
13
|
+
type: "problem",
|
|
14
|
+
docs: { description: "Disallow invalid Master CSS classes" },
|
|
15
|
+
messages: {
|
|
16
|
+
invalidClass: "{{message}}",
|
|
17
|
+
disallowUnknownClass: "{{message}}"
|
|
18
|
+
},
|
|
19
|
+
fixable: null,
|
|
20
|
+
schema: [noInvalidClassesOptionsSchema]
|
|
21
|
+
},
|
|
22
|
+
defaultOptions: [],
|
|
23
|
+
create: function(context) {
|
|
24
|
+
const { options, settings, tooling, release } = resolveContext(context);
|
|
25
|
+
if (shouldUseSourceVisitors(context)) return withContextRelease(defineSourceVisitors({
|
|
26
|
+
context,
|
|
27
|
+
tooling,
|
|
28
|
+
ruleId: "no-invalid-classes",
|
|
29
|
+
ruleOptions: { disallowUnknownClass: options.disallowUnknownClass }
|
|
30
|
+
}), release);
|
|
31
|
+
return withContextRelease(defineVisitors({
|
|
32
|
+
context,
|
|
33
|
+
settings,
|
|
34
|
+
tooling
|
|
35
|
+
}, (node, resolved) => {
|
|
36
|
+
const diagnostics = createMasterCSSLintDiagnostics(tooling.analyzeLintClassList(resolved.analysisText ?? resolved.raw, resolved.classValues, { disallowUnknownClass: options.disallowUnknownClass }).diagnostics.filter(({ ruleId }) => ruleId === "no-invalid-classes"), "error");
|
|
37
|
+
reportLintDiagnostics(context, node, resolved, diagnostics);
|
|
38
|
+
}), release);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
export { no_invalid_classes_default as default };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"unapprovedRawValue", [{
|
|
2
|
+
allowRawValues: boolean;
|
|
3
|
+
allowProperties: any[];
|
|
4
|
+
allowedPatterns: any[];
|
|
5
|
+
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
export { _default as default };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import create_rule_default from "../create-rule.js";
|
|
2
|
+
import defineVisitors from "../utils/define-visitors.js";
|
|
3
|
+
import resolveContext from "../utils/resolve-context.js";
|
|
4
|
+
import reportLintDiagnostics from "../utils/report-lint-diagnostics.js";
|
|
5
|
+
import defineSourceVisitors, { shouldUseSourceVisitors } from "../utils/define-source-visitors.js";
|
|
6
|
+
import withContextRelease from "../utils/with-context-release.js";
|
|
7
|
+
import { createMasterCSSLintDiagnostics } from "@master/css-tooling/lint";
|
|
8
|
+
// src/rules/no-unapproved-raw-values.ts
|
|
9
|
+
var no_unapproved_raw_values_default = create_rule_default({
|
|
10
|
+
name: "no-unapproved-raw-values",
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: { description: "Disallow unapproved raw values in token-backed Master CSS classes" },
|
|
14
|
+
messages: { unapprovedRawValue: "{{message}}" },
|
|
15
|
+
fixable: null,
|
|
16
|
+
schema: [{
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
allowRawValues: { type: "boolean" },
|
|
20
|
+
allowProperties: {
|
|
21
|
+
type: "array",
|
|
22
|
+
items: { type: "string" },
|
|
23
|
+
uniqueItems: true
|
|
24
|
+
},
|
|
25
|
+
requireProperties: {
|
|
26
|
+
type: "array",
|
|
27
|
+
items: { type: "string" },
|
|
28
|
+
uniqueItems: true
|
|
29
|
+
},
|
|
30
|
+
allowedPatterns: {
|
|
31
|
+
type: "array",
|
|
32
|
+
items: { type: "string" },
|
|
33
|
+
uniqueItems: true
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
additionalProperties: false
|
|
37
|
+
}]
|
|
38
|
+
},
|
|
39
|
+
defaultOptions: [{
|
|
40
|
+
allowRawValues: false,
|
|
41
|
+
allowProperties: [],
|
|
42
|
+
allowedPatterns: []
|
|
43
|
+
}],
|
|
44
|
+
create(context) {
|
|
45
|
+
const { settings, tooling, release } = resolveContext(context);
|
|
46
|
+
const options = context.options[0] || {};
|
|
47
|
+
if (shouldUseSourceVisitors(context)) return withContextRelease(defineSourceVisitors({
|
|
48
|
+
context,
|
|
49
|
+
tooling,
|
|
50
|
+
ruleId: "no-unapproved-raw-values",
|
|
51
|
+
ruleOptions: options
|
|
52
|
+
}), release);
|
|
53
|
+
return withContextRelease(defineVisitors({
|
|
54
|
+
context,
|
|
55
|
+
settings,
|
|
56
|
+
tooling
|
|
57
|
+
}, (node, resolved) => {
|
|
58
|
+
const diagnostics = createMasterCSSLintDiagnostics(tooling.analyzeLintClassList(resolved.analysisText ?? resolved.raw, resolved.classValues, { rawValuePolicy: options }).diagnostics.filter(({ ruleId }) => ruleId === "no-unapproved-raw-values"));
|
|
59
|
+
reportLintDiagnostics(context, node, resolved, diagnostics);
|
|
60
|
+
}), release);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
export { no_unapproved_raw_values_default as default };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { CanonicalClassNameOptions } from "@master/css-tooling/lint";
|
|
2
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferClass", [Readonly<Required<CanonicalClassNameOptions>>], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export { _default as default };
|