@friendsoftheweb/eslint-plugin 0.0.1 → 0.0.2
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 +74 -2
- package/dist/cjs/index.js +346 -32
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +346 -32
- package/dist/esm/index.js.map +1 -1
- package/dist/types/rules/ban-lodash-import.d.mts +24 -0
- package/dist/types/rules/css-module-class-exists.d.mts +1 -0
- package/dist/types/rules/css-module-name-matches.d.mts +1 -0
- package/dist/types/rules/valid-server-actions-path.d.mts +23 -0
- package/package.json +15 -13
- package/dist/cjs/rules/css-module-class-exists.js +0 -215
- package/dist/cjs/rules/css-module-class-exists.js.map +0 -1
- package/dist/cjs/rules/css-module-name-matches.js +0 -54
- package/dist/cjs/rules/css-module-name-matches.js.map +0 -1
- package/dist/esm/rules/css-module-class-exists.js +0 -213
- package/dist/esm/rules/css-module-class-exists.js.map +0 -1
- package/dist/esm/rules/css-module-name-matches.js +0 -52
- package/dist/esm/rules/css-module-name-matches.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,9 +6,59 @@
|
|
|
6
6
|
yarn add -D @friendsoftheweb/eslint-plugin
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
+
## Rules
|
|
10
|
+
|
|
11
|
+
### `friendsoftheweb/ban-lodash-import`
|
|
12
|
+
|
|
13
|
+
Enforces importing functions from `lodash-es` instead of `lodash`.
|
|
14
|
+
|
|
15
|
+
This rule helps ensure tree shaking works properly by preferring ES module
|
|
16
|
+
imports from `lodash-es` over CommonJS imports from `lodash`.
|
|
17
|
+
|
|
18
|
+
#### Examples
|
|
19
|
+
|
|
20
|
+
❌ **Incorrect:**
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
import _ from 'lodash';
|
|
24
|
+
import { map } from 'lodash';
|
|
25
|
+
import debounce from 'lodash/debounce';
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
✅ **Correct:**
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
import { map } from 'lodash-es';
|
|
32
|
+
import debounce from 'lodash-es/debounce';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Note:** This rule provides automatic fixes for most cases, except for
|
|
36
|
+
`lodash/fp` imports which require manual migration.
|
|
37
|
+
|
|
38
|
+
### `friendsoftheweb/css-module-class-exists`
|
|
39
|
+
|
|
40
|
+
Enforces that class names used from an imported CSS module exist in the module
|
|
41
|
+
file.
|
|
42
|
+
|
|
43
|
+
### `friendsoftheweb/css-module-name-matches`
|
|
44
|
+
|
|
45
|
+
Enforces that a CSS module's filename matches the filename of the importing
|
|
46
|
+
file.
|
|
47
|
+
|
|
48
|
+
This rule ensures consistent naming conventions by requiring CSS module files to
|
|
49
|
+
have the same base name as the file importing them.
|
|
50
|
+
|
|
51
|
+
### `friendsoftheweb/valid-server-actions-path`
|
|
52
|
+
|
|
53
|
+
Enforces server actions are exported from file paths that match
|
|
54
|
+
`app/**/_actions.ts` or `app/**/_actions/**/*.ts`.
|
|
55
|
+
|
|
56
|
+
This rule helps maintain a consistent file structure for Next.js server actions
|
|
57
|
+
by ensuring they are placed in designated locations.
|
|
58
|
+
|
|
9
59
|
## Example Configurations
|
|
10
60
|
|
|
11
|
-
|
|
61
|
+
### Basic Example
|
|
12
62
|
|
|
13
63
|
```javascript
|
|
14
64
|
import friendsOfTheWeb from '@friendsoftheweb/eslint-plugin';
|
|
@@ -27,7 +77,29 @@ export default defineConfig([
|
|
|
27
77
|
]);
|
|
28
78
|
```
|
|
29
79
|
|
|
30
|
-
|
|
80
|
+
### Gradual Adoption
|
|
81
|
+
|
|
82
|
+
There is an additional configuration that makes it easier to adopt this plugin
|
|
83
|
+
by only warning about violations.
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
import friendsOfTheWeb from '@friendsoftheweb/eslint-plugin';
|
|
87
|
+
import { defineConfig } from 'eslint/config';
|
|
88
|
+
import tseslint from 'typescript-eslint';
|
|
89
|
+
|
|
90
|
+
export default defineConfig([
|
|
91
|
+
{ ignores: ['.yarn/**/*'] },
|
|
92
|
+
{
|
|
93
|
+
files: ['**/*.{js,jsx,ts,tsx}'],
|
|
94
|
+
extends: [
|
|
95
|
+
tseslint.configs.recommended,
|
|
96
|
+
friendsOfTheWeb.configs['flat/migrate'],
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
]);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Example with React
|
|
31
103
|
|
|
32
104
|
```javascript
|
|
33
105
|
import friendsOfTheWeb from '@friendsoftheweb/eslint-plugin';
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,43 +1,357 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var path = require('node:path');
|
|
4
|
+
var fs = require('node:fs');
|
|
5
|
+
var postcss = require('postcss');
|
|
6
|
+
var selectorParser = require('postcss-selector-parser');
|
|
7
|
+
|
|
8
|
+
var name = "@friendsoftheweb/eslint-plugin";
|
|
9
|
+
var version = "0.0.2";
|
|
10
|
+
var packageJson = {
|
|
11
|
+
name: name,
|
|
12
|
+
version: version};
|
|
13
|
+
|
|
14
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
15
|
+
var banLodashImport = {
|
|
16
|
+
meta: {
|
|
17
|
+
type: 'problem',
|
|
18
|
+
fixable: 'code',
|
|
19
|
+
docs: {
|
|
20
|
+
description: 'enforce importing functions from `lodash-es` instead of `lodash`',
|
|
21
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebban-lodash-import',
|
|
22
|
+
},
|
|
23
|
+
schema: [],
|
|
24
|
+
messages: {
|
|
25
|
+
invalidImport: 'Functions must be imported from "lodash-es" instead of "lodash"',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
create(context) {
|
|
29
|
+
return {
|
|
30
|
+
ImportDeclaration(node) {
|
|
31
|
+
if (typeof node.source.value !== 'string' ||
|
|
32
|
+
(node.source.value !== 'lodash' &&
|
|
33
|
+
!node.source.value.startsWith('lodash/'))) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
context.report({
|
|
37
|
+
node,
|
|
38
|
+
messageId: 'invalidImport',
|
|
39
|
+
fix(fixer) {
|
|
40
|
+
if (typeof node.source.value !== 'string') {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
if (node.source.value === 'lodash/fp') {
|
|
44
|
+
return null; // no automatic fix for fp imports
|
|
45
|
+
}
|
|
46
|
+
const newImportPath = node.source.value === 'lodash'
|
|
47
|
+
? 'lodash-es'
|
|
48
|
+
: node.source.value.replace(/^lodash\//, 'lodash-es/');
|
|
49
|
+
const quote = node.source.raw[0]; // preserve original quote style
|
|
50
|
+
return fixer.replaceText(node.source, `${quote}${newImportPath}${quote}`);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
59
|
+
var cssModuleNameMatchesRule = {
|
|
60
|
+
meta: {
|
|
61
|
+
type: 'problem',
|
|
62
|
+
docs: {
|
|
63
|
+
description: "enforce that a CSS module's filename matches the filename of the importing file",
|
|
64
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebcss-module-name-matches',
|
|
65
|
+
},
|
|
66
|
+
schema: [],
|
|
67
|
+
messages: {
|
|
68
|
+
filenameMismatch: 'CSS module filename "{{cssModuleFilename}}" does not match the current filename "{{filename}}"',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
create(context) {
|
|
72
|
+
return {
|
|
73
|
+
ImportDeclaration(node) {
|
|
74
|
+
if (typeof node.source.value !== 'string' ||
|
|
75
|
+
!node.source.value.endsWith('.module.css')) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const filename = path.basename(context.filename, path.extname(context.filename));
|
|
79
|
+
const cssModulePath = node.source.value;
|
|
80
|
+
const cssModuleFilename = path.basename(cssModulePath, '.module.css');
|
|
81
|
+
if (cssModuleFilename !== filename) {
|
|
82
|
+
context.report({
|
|
83
|
+
node,
|
|
84
|
+
messageId: 'filenameMismatch',
|
|
85
|
+
data: {
|
|
86
|
+
cssModuleFilename,
|
|
87
|
+
filename,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
97
|
+
var cssModuleClassExistsRule = {
|
|
98
|
+
meta: {
|
|
99
|
+
type: 'problem',
|
|
100
|
+
docs: {
|
|
101
|
+
description: 'enforce that class names used from an imported CSS module exist in the module file',
|
|
102
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebcss-module-class-exists',
|
|
103
|
+
},
|
|
104
|
+
schema: [],
|
|
105
|
+
messages: {
|
|
106
|
+
relativePath: 'CSS module import "{{importPath}}" should be a relative path',
|
|
107
|
+
defaultImport: 'CSS module import "{{importPath}}" should have a default import',
|
|
108
|
+
onlyDefaultImport: 'CSS module import "{{importPath}}" should have only a default import',
|
|
109
|
+
fileDoesNotExist: 'CSS module file "{{absoluteImportPath}}" does not exist',
|
|
110
|
+
classDoesNotExist: 'Class `.{{className}}` does not exist in the CSS module imported as `{{objectName}}`',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
create(context) {
|
|
114
|
+
const classNames = {};
|
|
115
|
+
return {
|
|
116
|
+
ImportDeclaration(node) {
|
|
117
|
+
if (typeof node.source.value !== 'string' ||
|
|
118
|
+
!node.source.value.endsWith('.module.css')) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const importPath = node.source.value;
|
|
122
|
+
if (!(importPath.startsWith('./') || importPath.startsWith('../'))) {
|
|
123
|
+
context.report({
|
|
124
|
+
node,
|
|
125
|
+
messageId: 'relativePath',
|
|
126
|
+
data: { importPath },
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (node.specifiers.length === 0) {
|
|
131
|
+
context.report({
|
|
132
|
+
node,
|
|
133
|
+
messageId: 'defaultImport',
|
|
134
|
+
data: { importPath },
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (node.specifiers.length > 1) {
|
|
139
|
+
context.report({
|
|
140
|
+
node,
|
|
141
|
+
messageId: 'onlyDefaultImport',
|
|
142
|
+
data: { importPath },
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const defaultImportSpecifier = node.specifiers.find((specifier) => specifier.type === 'ImportDefaultSpecifier');
|
|
147
|
+
if (defaultImportSpecifier == null) {
|
|
148
|
+
context.report({
|
|
149
|
+
node,
|
|
150
|
+
messageId: 'onlyDefaultImport',
|
|
151
|
+
data: { importPath },
|
|
152
|
+
});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const dirname = path.dirname(context.physicalFilename);
|
|
156
|
+
const absoluteImportPath = path.resolve(dirname, importPath);
|
|
157
|
+
if (!fs.existsSync(absoluteImportPath)) {
|
|
158
|
+
context.report({
|
|
159
|
+
node,
|
|
160
|
+
messageId: 'fileDoesNotExist',
|
|
161
|
+
data: { absoluteImportPath },
|
|
162
|
+
});
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const importName = defaultImportSpecifier.local.name;
|
|
166
|
+
classNames[importName] = new Set();
|
|
167
|
+
const cssModuleContent = fs.readFileSync(absoluteImportPath, 'utf8');
|
|
168
|
+
const root = postcss.parse(cssModuleContent);
|
|
169
|
+
for (const node of root.nodes) {
|
|
170
|
+
if (node.type === 'rule') {
|
|
171
|
+
selectorParser(function transform(selectors) {
|
|
172
|
+
selectors.walkClasses((classNode) => {
|
|
173
|
+
classNames[importName].add(classNode.value);
|
|
174
|
+
});
|
|
175
|
+
}).processSync(node.selector);
|
|
176
|
+
}
|
|
177
|
+
else if (node.type === 'atrule' &&
|
|
178
|
+
(node.name === 'media' ||
|
|
179
|
+
node.name === 'container' ||
|
|
180
|
+
node.name === 'layer')) {
|
|
181
|
+
for (const childNode of node.nodes) {
|
|
182
|
+
if (childNode.type !== 'rule') {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
selectorParser(function transform(selectors) {
|
|
186
|
+
selectors.walkClasses((classNode) => {
|
|
187
|
+
classNames[importName].add(classNode.value);
|
|
188
|
+
});
|
|
189
|
+
}).processSync(childNode.selector);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
MemberExpression(node) {
|
|
195
|
+
if (node.object.type !== 'Identifier') {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (classNames[node.object.name] == null) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const objectName = node.object.name;
|
|
202
|
+
if (node.property.type === 'Identifier') {
|
|
203
|
+
const className = node.property.name;
|
|
204
|
+
if (!classNames[objectName].has(className)) {
|
|
205
|
+
context.report({
|
|
206
|
+
node,
|
|
207
|
+
messageId: 'classDoesNotExist',
|
|
208
|
+
data: { className, objectName },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (node.property.type === 'Literal' &&
|
|
214
|
+
typeof node.property.value === 'string') {
|
|
215
|
+
const className = node.property.value;
|
|
216
|
+
if (!classNames[objectName].has(className)) {
|
|
217
|
+
context.report({
|
|
218
|
+
node,
|
|
219
|
+
messageId: 'classDoesNotExist',
|
|
220
|
+
data: { className, objectName },
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
VariableDeclarator(node) {
|
|
226
|
+
var _a;
|
|
227
|
+
if (node.id.type !== 'ObjectPattern') {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (((_a = node.init) === null || _a === void 0 ? void 0 : _a.type) !== 'Identifier') {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const objectName = node.init.name;
|
|
234
|
+
if (classNames[objectName] == null) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
for (const property of node.id.properties) {
|
|
238
|
+
if (property.type !== 'Property') {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (property.key.type !== 'Identifier') {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const className = property.key.name;
|
|
245
|
+
if (!classNames[objectName].has(className)) {
|
|
246
|
+
context.report({
|
|
247
|
+
node: property,
|
|
248
|
+
messageId: 'classDoesNotExist',
|
|
249
|
+
data: { className, objectName },
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
259
|
+
var validServerActionsPathRule = {
|
|
260
|
+
meta: {
|
|
261
|
+
type: 'problem',
|
|
262
|
+
docs: {
|
|
263
|
+
description: 'enforce server actions are exported from file paths that match "app/**/_actions.ts" or "app/**/_actions/**/*.ts"',
|
|
264
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebvalid-server-actions-path',
|
|
265
|
+
},
|
|
266
|
+
schema: [],
|
|
267
|
+
messages: {
|
|
268
|
+
invalidPath: 'Server action files must be located in a directory named "_actions" or have the filename "_actions.ts"',
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
create(context) {
|
|
272
|
+
return {
|
|
273
|
+
ExpressionStatement(node) {
|
|
274
|
+
if (node.expression.type !== 'Literal' ||
|
|
275
|
+
node.expression.value !== 'use server') {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const basename = path.basename(context.filename);
|
|
279
|
+
const dirname = path.dirname(context.filename);
|
|
280
|
+
// Escape backslashes for RegExp (Windows paths)
|
|
281
|
+
const escapedSep = path.sep.replace('\\', '\\\\');
|
|
282
|
+
const isInActionsDir = new RegExp(`app(${escapedSep}.*)?${escapedSep}_actions`).test(dirname);
|
|
283
|
+
const isActionsFile = (dirname === 'app' || new RegExp(`app${escapedSep}`).test(dirname)) &&
|
|
284
|
+
/_actions\.(js|ts)$/.test(basename);
|
|
285
|
+
if (!isInActionsDir && !isActionsFile) {
|
|
286
|
+
context.report({
|
|
287
|
+
node,
|
|
288
|
+
messageId: 'invalidPath',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
},
|
|
294
|
+
};
|
|
5
295
|
|
|
6
296
|
/** @type {import('eslint').ESLint.Plugin} */
|
|
7
297
|
const plugin = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
298
|
+
meta: {
|
|
299
|
+
name: packageJson.name,
|
|
300
|
+
version: packageJson.version,
|
|
301
|
+
},
|
|
302
|
+
configs: {},
|
|
303
|
+
rules: {
|
|
304
|
+
'ban-lodash-import': banLodashImport,
|
|
305
|
+
'css-module-name-matches': cssModuleNameMatchesRule,
|
|
306
|
+
'css-module-class-exists': cssModuleClassExistsRule,
|
|
307
|
+
'valid-server-actions-path': validServerActionsPathRule,
|
|
308
|
+
},
|
|
17
309
|
};
|
|
18
|
-
|
|
19
310
|
Object.assign(plugin.configs, {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
311
|
+
'flat/recommended': [
|
|
312
|
+
{
|
|
313
|
+
plugins: {
|
|
314
|
+
friendsoftheweb: plugin,
|
|
315
|
+
},
|
|
316
|
+
rules: {
|
|
317
|
+
'friendsoftheweb/ban-lodash-import': 'error',
|
|
318
|
+
'friendsoftheweb/css-module-name-matches': 'error',
|
|
319
|
+
'friendsoftheweb/css-module-class-exists': 'error',
|
|
320
|
+
'friendsoftheweb/valid-server-actions-path': 'error',
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
'flat/migrate': [
|
|
325
|
+
{
|
|
326
|
+
plugins: {
|
|
327
|
+
friendsoftheweb: plugin,
|
|
328
|
+
},
|
|
329
|
+
rules: {
|
|
330
|
+
'friendsoftheweb/ban-lodash-import': 'warn',
|
|
331
|
+
'friendsoftheweb/css-module-name-matches': 'warn',
|
|
332
|
+
'friendsoftheweb/css-module-class-exists': 'warn',
|
|
333
|
+
'friendsoftheweb/valid-server-actions-path': 'warn',
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
recommended: {
|
|
338
|
+
plugins: { friendsoftheweb: plugin },
|
|
339
|
+
rules: {
|
|
340
|
+
'friendsoftheweb/ban-lodash-import': 'error',
|
|
341
|
+
'friendsoftheweb/css-module-name-matches': 'error',
|
|
342
|
+
'friendsoftheweb/css-module-class-exists': 'error',
|
|
343
|
+
'friendsoftheweb/valid-server-actions-path': 'error',
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
migrate: {
|
|
347
|
+
plugins: { friendsoftheweb: plugin },
|
|
348
|
+
rules: {
|
|
349
|
+
'friendsoftheweb/ban-lodash-import': 'warn',
|
|
350
|
+
'friendsoftheweb/css-module-name-matches': 'warn',
|
|
351
|
+
'friendsoftheweb/css-module-class-exists': 'warn',
|
|
352
|
+
'friendsoftheweb/valid-server-actions-path': 'warn',
|
|
353
|
+
},
|
|
39
354
|
},
|
|
40
|
-
},
|
|
41
355
|
});
|
|
42
356
|
|
|
43
357
|
module.exports = plugin;
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/index.mjs"],"sourcesContent":["import cssModuleNameMatchesRule from './rules/css-module-name-matches.mjs';\nimport cssModuleClassExistsRule from './rules/css-module-class-exists.mjs';\n\n/** @type {import('eslint').ESLint.Plugin} */\nconst plugin = {\n meta: {\n name: '@friendsoftheweb/eslint-plugin',\n version: '0.0.1',\n },\n configs: {},\n rules: {\n 'css-module-name-matches': cssModuleNameMatchesRule,\n 'css-module-class-exists': cssModuleClassExistsRule,\n },\n};\n\nObject.assign(plugin.configs, {\n // flat config format\n 'flat/recommended': [\n {\n plugins: {\n friendsoftheweb: plugin,\n },\n rules: {\n 'friendsoftheweb/css-module-name-matches': 'error',\n 'friendsoftheweb/css-module-class-exists': 'error',\n },\n },\n ],\n\n // eslintrc format\n recommended: {\n plugins: { friendsoftheweb: plugin },\n rules: {\n 'friendsoftheweb/css-module-name-matches': 'error',\n 'friendsoftheweb/css-module-class-exists': 'error',\n },\n },\n});\n\nexport default plugin;\n"],"names":["cssModuleNameMatchesRule","cssModuleClassExistsRule"],"mappings":";;;;;AAGA;AACK,MAAC,MAAM,GAAG;AACf,EAAE,IAAI,EAAE;AACR,IAAI,IAAI,EAAE,gCAAgC;AAC1C,IAAI,OAAO,EAAE,OAAO;AACpB,GAAG;AACH,EAAE,OAAO,EAAE,EAAE;AACb,EAAE,KAAK,EAAE;AACT,IAAI,yBAAyB,EAAEA,oBAAwB;AACvD,IAAI,yBAAyB,EAAEC,oBAAwB;AACvD,GAAG;AACH;;AAEA,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;AAC9B;AACA,EAAE,kBAAkB,EAAE;AACtB,IAAI;AACJ,MAAM,OAAO,EAAE;AACf,QAAQ,eAAe,EAAE,MAAM;AAC/B,OAAO;AACP,MAAM,KAAK,EAAE;AACb,QAAQ,yCAAyC,EAAE,OAAO;AAC1D,QAAQ,yCAAyC,EAAE,OAAO;AAC1D,OAAO;AACP,KAAK;AACL,GAAG;;AAEH;AACA,EAAE,WAAW,EAAE;AACf,IAAI,OAAO,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE;AACxC,IAAI,KAAK,EAAE;AACX,MAAM,yCAAyC,EAAE,OAAO;AACxD,MAAM,yCAAyC,EAAE,OAAO;AACxD,KAAK;AACL,GAAG;AACH,CAAC,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/rules/ban-lodash-import.mjs","../../../../src/rules/css-module-name-matches.mjs","../../../../src/rules/css-module-class-exists.mjs","../../../../src/rules/valid-server-actions-path.mjs","../../../../src/index.mjs"],"sourcesContent":["/** @type {import('eslint').JSRuleDefinition} */\nexport default {\n meta: {\n type: 'problem',\n fixable: 'code',\n docs: {\n description:\n 'enforce importing functions from `lodash-es` instead of `lodash`',\n url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebban-lodash-import',\n },\n schema: [],\n messages: {\n invalidImport:\n 'Functions must be imported from \"lodash-es\" instead of \"lodash\"',\n },\n },\n create(context) {\n return {\n ImportDeclaration(node) {\n if (\n typeof node.source.value !== 'string' ||\n (node.source.value !== 'lodash' &&\n !node.source.value.startsWith('lodash/'))\n ) {\n return;\n }\n\n context.report({\n node,\n messageId: 'invalidImport',\n fix(fixer) {\n if (typeof node.source.value !== 'string') {\n return null;\n }\n\n if (node.source.value === 'lodash/fp') {\n return null; // no automatic fix for fp imports\n }\n\n const newImportPath =\n node.source.value === 'lodash'\n ? 'lodash-es'\n : node.source.value.replace(/^lodash\\//, 'lodash-es/');\n\n const quote = node.source.raw[0]; // preserve original quote style\n\n return fixer.replaceText(\n node.source,\n `${quote}${newImportPath}${quote}`,\n );\n },\n });\n },\n };\n },\n};\n","import path from 'node:path';\n\n/** @type {import('eslint').JSRuleDefinition} */\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description:\n \"enforce that a CSS module's filename matches the filename of the importing file\",\n url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebcss-module-name-matches',\n },\n schema: [],\n messages: {\n filenameMismatch:\n 'CSS module filename \"{{cssModuleFilename}}\" does not match the current filename \"{{filename}}\"',\n },\n },\n create(context) {\n return {\n ImportDeclaration(node) {\n if (\n typeof node.source.value !== 'string' ||\n !node.source.value.endsWith('.module.css')\n ) {\n return;\n }\n\n const filename = path.basename(\n context.filename,\n path.extname(context.filename),\n );\n\n const cssModulePath = node.source.value;\n const cssModuleFilename = path.basename(cssModulePath, '.module.css');\n\n if (cssModuleFilename !== filename) {\n context.report({\n node,\n messageId: 'filenameMismatch',\n data: {\n cssModuleFilename,\n filename,\n },\n });\n }\n },\n };\n },\n};\n","import path from 'node:path';\nimport fs from 'node:fs';\n\nimport { parse } from 'postcss';\nimport selectorParser from 'postcss-selector-parser';\n\n/** @type {import('eslint').JSRuleDefinition} */\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'enforce that class names used from an imported CSS module exist in the module file',\n url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebcss-module-class-exists',\n },\n schema: [],\n messages: {\n relativePath:\n 'CSS module import \"{{importPath}}\" should be a relative path',\n defaultImport:\n 'CSS module import \"{{importPath}}\" should have a default import',\n onlyDefaultImport:\n 'CSS module import \"{{importPath}}\" should have only a default import',\n fileDoesNotExist:\n 'CSS module file \"{{absoluteImportPath}}\" does not exist',\n classDoesNotExist:\n 'Class `.{{className}}` does not exist in the CSS module imported as `{{objectName}}`',\n },\n },\n create(context) {\n const classNames = {};\n\n return {\n ImportDeclaration(node) {\n if (\n typeof node.source.value !== 'string' ||\n !node.source.value.endsWith('.module.css')\n ) {\n return;\n }\n\n const importPath = node.source.value;\n\n if (!(importPath.startsWith('./') || importPath.startsWith('../'))) {\n context.report({\n node,\n messageId: 'relativePath',\n data: { importPath },\n });\n\n return;\n }\n\n if (node.specifiers.length === 0) {\n context.report({\n node,\n messageId: 'defaultImport',\n data: { importPath },\n });\n\n return;\n }\n\n if (node.specifiers.length > 1) {\n context.report({\n node,\n messageId: 'onlyDefaultImport',\n data: { importPath },\n });\n\n return;\n }\n\n const defaultImportSpecifier = node.specifiers.find(\n (specifier) => specifier.type === 'ImportDefaultSpecifier',\n );\n\n if (defaultImportSpecifier == null) {\n context.report({\n node,\n messageId: 'onlyDefaultImport',\n data: { importPath },\n });\n\n return;\n }\n\n const dirname = path.dirname(context.physicalFilename);\n const absoluteImportPath = path.resolve(dirname, importPath);\n\n if (!fs.existsSync(absoluteImportPath)) {\n context.report({\n node,\n messageId: 'fileDoesNotExist',\n data: { absoluteImportPath },\n });\n\n return;\n }\n\n const importName = defaultImportSpecifier.local.name;\n\n classNames[importName] = new Set();\n\n const cssModuleContent = fs.readFileSync(absoluteImportPath, 'utf8');\n const root = parse(cssModuleContent);\n\n for (const node of root.nodes) {\n if (node.type === 'rule') {\n selectorParser(function transform(selectors) {\n selectors.walkClasses((classNode) => {\n classNames[importName].add(classNode.value);\n });\n }).processSync(node.selector);\n } else if (\n node.type === 'atrule' &&\n (node.name === 'media' ||\n node.name === 'container' ||\n node.name === 'layer')\n ) {\n for (const childNode of node.nodes) {\n if (childNode.type !== 'rule') {\n continue;\n }\n\n selectorParser(function transform(selectors) {\n selectors.walkClasses((classNode) => {\n classNames[importName].add(classNode.value);\n });\n }).processSync(childNode.selector);\n }\n }\n }\n },\n MemberExpression(node) {\n if (node.object.type !== 'Identifier') {\n return;\n }\n\n if (classNames[node.object.name] == null) {\n return;\n }\n\n const objectName = node.object.name;\n\n if (node.property.type === 'Identifier') {\n const className = node.property.name;\n\n if (!classNames[objectName].has(className)) {\n context.report({\n node,\n messageId: 'classDoesNotExist',\n data: { className, objectName },\n });\n }\n\n return;\n }\n\n if (\n node.property.type === 'Literal' &&\n typeof node.property.value === 'string'\n ) {\n const className = node.property.value;\n\n if (!classNames[objectName].has(className)) {\n context.report({\n node,\n messageId: 'classDoesNotExist',\n data: { className, objectName },\n });\n }\n }\n },\n VariableDeclarator(node) {\n if (node.id.type !== 'ObjectPattern') {\n return;\n }\n\n if (node.init?.type !== 'Identifier') {\n return;\n }\n\n const objectName = node.init.name;\n\n if (classNames[objectName] == null) {\n return;\n }\n\n for (const property of node.id.properties) {\n if (property.type !== 'Property') {\n continue;\n }\n\n if (property.key.type !== 'Identifier') {\n continue;\n }\n\n const className = property.key.name;\n\n if (!classNames[objectName].has(className)) {\n context.report({\n node: property,\n messageId: 'classDoesNotExist',\n data: { className, objectName },\n });\n }\n }\n },\n };\n },\n};\n","import path from 'node:path';\n\n/** @type {import('eslint').JSRuleDefinition} */\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'enforce server actions are exported from file paths that match \"app/**/_actions.ts\" or \"app/**/_actions/**/*.ts\"',\n url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebvalid-server-actions-path',\n },\n schema: [],\n messages: {\n invalidPath:\n 'Server action files must be located in a directory named \"_actions\" or have the filename \"_actions.ts\"',\n },\n },\n create(context) {\n return {\n ExpressionStatement(node) {\n if (\n node.expression.type !== 'Literal' ||\n node.expression.value !== 'use server'\n ) {\n return;\n }\n\n const basename = path.basename(context.filename);\n const dirname = path.dirname(context.filename);\n\n // Escape backslashes for RegExp (Windows paths)\n const escapedSep = path.sep.replace('\\\\', '\\\\\\\\');\n\n const isInActionsDir = new RegExp(\n `app(${escapedSep}.*)?${escapedSep}_actions`,\n ).test(dirname);\n\n const isActionsFile =\n (dirname === 'app' || new RegExp(`app${escapedSep}`).test(dirname)) &&\n /_actions\\.(js|ts)$/.test(basename);\n\n if (!isInActionsDir && !isActionsFile) {\n context.report({\n node,\n messageId: 'invalidPath',\n });\n }\n },\n };\n },\n};\n","import packageJson from '../package.json' with { type: 'json' };\n\nimport banLodashImport from './rules/ban-lodash-import.mjs';\nimport cssModuleNameMatchesRule from './rules/css-module-name-matches.mjs';\nimport cssModuleClassExistsRule from './rules/css-module-class-exists.mjs';\nimport validServerActionsPathRule from './rules/valid-server-actions-path.mjs';\n\n/** @type {import('eslint').ESLint.Plugin} */\nconst plugin = {\n meta: {\n name: packageJson.name,\n version: packageJson.version,\n },\n configs: {},\n rules: {\n 'ban-lodash-import': banLodashImport,\n 'css-module-name-matches': cssModuleNameMatchesRule,\n 'css-module-class-exists': cssModuleClassExistsRule,\n 'valid-server-actions-path': validServerActionsPathRule,\n },\n};\n\nObject.assign(plugin.configs, {\n 'flat/recommended': [\n {\n plugins: {\n friendsoftheweb: plugin,\n },\n rules: {\n 'friendsoftheweb/ban-lodash-import': 'error',\n 'friendsoftheweb/css-module-name-matches': 'error',\n 'friendsoftheweb/css-module-class-exists': 'error',\n 'friendsoftheweb/valid-server-actions-path': 'error',\n },\n },\n ],\n\n 'flat/migrate': [\n {\n plugins: {\n friendsoftheweb: plugin,\n },\n rules: {\n 'friendsoftheweb/ban-lodash-import': 'warn',\n 'friendsoftheweb/css-module-name-matches': 'warn',\n 'friendsoftheweb/css-module-class-exists': 'warn',\n 'friendsoftheweb/valid-server-actions-path': 'warn',\n },\n },\n ],\n\n recommended: {\n plugins: { friendsoftheweb: plugin },\n rules: {\n 'friendsoftheweb/ban-lodash-import': 'error',\n 'friendsoftheweb/css-module-name-matches': 'error',\n 'friendsoftheweb/css-module-class-exists': 'error',\n 'friendsoftheweb/valid-server-actions-path': 'error',\n },\n },\n\n migrate: {\n plugins: { friendsoftheweb: plugin },\n rules: {\n 'friendsoftheweb/ban-lodash-import': 'warn',\n 'friendsoftheweb/css-module-name-matches': 'warn',\n 'friendsoftheweb/css-module-class-exists': 'warn',\n 'friendsoftheweb/valid-server-actions-path': 'warn',\n },\n },\n});\n\nexport default plugin;\n"],"names":["parse"],"mappings":"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"}
|