@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/dist/esm/index.js
CHANGED
|
@@ -1,41 +1,355 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { parse } from 'postcss';
|
|
4
|
+
import selectorParser from 'postcss-selector-parser';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
var name = "@friendsoftheweb/eslint-plugin";
|
|
7
|
+
var version = "0.0.2";
|
|
8
|
+
var packageJson = {
|
|
9
|
+
name: name,
|
|
10
|
+
version: version};
|
|
11
|
+
|
|
12
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
13
|
+
var banLodashImport = {
|
|
14
|
+
meta: {
|
|
15
|
+
type: 'problem',
|
|
16
|
+
fixable: 'code',
|
|
17
|
+
docs: {
|
|
18
|
+
description: 'enforce importing functions from `lodash-es` instead of `lodash`',
|
|
19
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebban-lodash-import',
|
|
20
|
+
},
|
|
21
|
+
schema: [],
|
|
22
|
+
messages: {
|
|
23
|
+
invalidImport: 'Functions must be imported from "lodash-es" instead of "lodash"',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
create(context) {
|
|
27
|
+
return {
|
|
28
|
+
ImportDeclaration(node) {
|
|
29
|
+
if (typeof node.source.value !== 'string' ||
|
|
30
|
+
(node.source.value !== 'lodash' &&
|
|
31
|
+
!node.source.value.startsWith('lodash/'))) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
context.report({
|
|
35
|
+
node,
|
|
36
|
+
messageId: 'invalidImport',
|
|
37
|
+
fix(fixer) {
|
|
38
|
+
if (typeof node.source.value !== 'string') {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (node.source.value === 'lodash/fp') {
|
|
42
|
+
return null; // no automatic fix for fp imports
|
|
43
|
+
}
|
|
44
|
+
const newImportPath = node.source.value === 'lodash'
|
|
45
|
+
? 'lodash-es'
|
|
46
|
+
: node.source.value.replace(/^lodash\//, 'lodash-es/');
|
|
47
|
+
const quote = node.source.raw[0]; // preserve original quote style
|
|
48
|
+
return fixer.replaceText(node.source, `${quote}${newImportPath}${quote}`);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
},
|
|
15
54
|
};
|
|
16
55
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
56
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
57
|
+
var cssModuleNameMatchesRule = {
|
|
58
|
+
meta: {
|
|
59
|
+
type: 'problem',
|
|
60
|
+
docs: {
|
|
61
|
+
description: "enforce that a CSS module's filename matches the filename of the importing file",
|
|
62
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebcss-module-name-matches',
|
|
63
|
+
},
|
|
64
|
+
schema: [],
|
|
65
|
+
messages: {
|
|
66
|
+
filenameMismatch: 'CSS module filename "{{cssModuleFilename}}" does not match the current filename "{{filename}}"',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
create(context) {
|
|
70
|
+
return {
|
|
71
|
+
ImportDeclaration(node) {
|
|
72
|
+
if (typeof node.source.value !== 'string' ||
|
|
73
|
+
!node.source.value.endsWith('.module.css')) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const filename = path.basename(context.filename, path.extname(context.filename));
|
|
77
|
+
const cssModulePath = node.source.value;
|
|
78
|
+
const cssModuleFilename = path.basename(cssModulePath, '.module.css');
|
|
79
|
+
if (cssModuleFilename !== filename) {
|
|
80
|
+
context.report({
|
|
81
|
+
node,
|
|
82
|
+
messageId: 'filenameMismatch',
|
|
83
|
+
data: {
|
|
84
|
+
cssModuleFilename,
|
|
85
|
+
filename,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
95
|
+
var cssModuleClassExistsRule = {
|
|
96
|
+
meta: {
|
|
97
|
+
type: 'problem',
|
|
98
|
+
docs: {
|
|
99
|
+
description: 'enforce that class names used from an imported CSS module exist in the module file',
|
|
100
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebcss-module-class-exists',
|
|
101
|
+
},
|
|
102
|
+
schema: [],
|
|
103
|
+
messages: {
|
|
104
|
+
relativePath: 'CSS module import "{{importPath}}" should be a relative path',
|
|
105
|
+
defaultImport: 'CSS module import "{{importPath}}" should have a default import',
|
|
106
|
+
onlyDefaultImport: 'CSS module import "{{importPath}}" should have only a default import',
|
|
107
|
+
fileDoesNotExist: 'CSS module file "{{absoluteImportPath}}" does not exist',
|
|
108
|
+
classDoesNotExist: 'Class `.{{className}}` does not exist in the CSS module imported as `{{objectName}}`',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
create(context) {
|
|
112
|
+
const classNames = {};
|
|
113
|
+
return {
|
|
114
|
+
ImportDeclaration(node) {
|
|
115
|
+
if (typeof node.source.value !== 'string' ||
|
|
116
|
+
!node.source.value.endsWith('.module.css')) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const importPath = node.source.value;
|
|
120
|
+
if (!(importPath.startsWith('./') || importPath.startsWith('../'))) {
|
|
121
|
+
context.report({
|
|
122
|
+
node,
|
|
123
|
+
messageId: 'relativePath',
|
|
124
|
+
data: { importPath },
|
|
125
|
+
});
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (node.specifiers.length === 0) {
|
|
129
|
+
context.report({
|
|
130
|
+
node,
|
|
131
|
+
messageId: 'defaultImport',
|
|
132
|
+
data: { importPath },
|
|
133
|
+
});
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (node.specifiers.length > 1) {
|
|
137
|
+
context.report({
|
|
138
|
+
node,
|
|
139
|
+
messageId: 'onlyDefaultImport',
|
|
140
|
+
data: { importPath },
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const defaultImportSpecifier = node.specifiers.find((specifier) => specifier.type === 'ImportDefaultSpecifier');
|
|
145
|
+
if (defaultImportSpecifier == null) {
|
|
146
|
+
context.report({
|
|
147
|
+
node,
|
|
148
|
+
messageId: 'onlyDefaultImport',
|
|
149
|
+
data: { importPath },
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const dirname = path.dirname(context.physicalFilename);
|
|
154
|
+
const absoluteImportPath = path.resolve(dirname, importPath);
|
|
155
|
+
if (!fs.existsSync(absoluteImportPath)) {
|
|
156
|
+
context.report({
|
|
157
|
+
node,
|
|
158
|
+
messageId: 'fileDoesNotExist',
|
|
159
|
+
data: { absoluteImportPath },
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const importName = defaultImportSpecifier.local.name;
|
|
164
|
+
classNames[importName] = new Set();
|
|
165
|
+
const cssModuleContent = fs.readFileSync(absoluteImportPath, 'utf8');
|
|
166
|
+
const root = parse(cssModuleContent);
|
|
167
|
+
for (const node of root.nodes) {
|
|
168
|
+
if (node.type === 'rule') {
|
|
169
|
+
selectorParser(function transform(selectors) {
|
|
170
|
+
selectors.walkClasses((classNode) => {
|
|
171
|
+
classNames[importName].add(classNode.value);
|
|
172
|
+
});
|
|
173
|
+
}).processSync(node.selector);
|
|
174
|
+
}
|
|
175
|
+
else if (node.type === 'atrule' &&
|
|
176
|
+
(node.name === 'media' ||
|
|
177
|
+
node.name === 'container' ||
|
|
178
|
+
node.name === 'layer')) {
|
|
179
|
+
for (const childNode of node.nodes) {
|
|
180
|
+
if (childNode.type !== 'rule') {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
selectorParser(function transform(selectors) {
|
|
184
|
+
selectors.walkClasses((classNode) => {
|
|
185
|
+
classNames[importName].add(classNode.value);
|
|
186
|
+
});
|
|
187
|
+
}).processSync(childNode.selector);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
MemberExpression(node) {
|
|
193
|
+
if (node.object.type !== 'Identifier') {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (classNames[node.object.name] == null) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const objectName = node.object.name;
|
|
200
|
+
if (node.property.type === 'Identifier') {
|
|
201
|
+
const className = node.property.name;
|
|
202
|
+
if (!classNames[objectName].has(className)) {
|
|
203
|
+
context.report({
|
|
204
|
+
node,
|
|
205
|
+
messageId: 'classDoesNotExist',
|
|
206
|
+
data: { className, objectName },
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (node.property.type === 'Literal' &&
|
|
212
|
+
typeof node.property.value === 'string') {
|
|
213
|
+
const className = node.property.value;
|
|
214
|
+
if (!classNames[objectName].has(className)) {
|
|
215
|
+
context.report({
|
|
216
|
+
node,
|
|
217
|
+
messageId: 'classDoesNotExist',
|
|
218
|
+
data: { className, objectName },
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
VariableDeclarator(node) {
|
|
224
|
+
var _a;
|
|
225
|
+
if (node.id.type !== 'ObjectPattern') {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (((_a = node.init) === null || _a === void 0 ? void 0 : _a.type) !== 'Identifier') {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const objectName = node.init.name;
|
|
232
|
+
if (classNames[objectName] == null) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
for (const property of node.id.properties) {
|
|
236
|
+
if (property.type !== 'Property') {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (property.key.type !== 'Identifier') {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const className = property.key.name;
|
|
243
|
+
if (!classNames[objectName].has(className)) {
|
|
244
|
+
context.report({
|
|
245
|
+
node: property,
|
|
246
|
+
messageId: 'classDoesNotExist',
|
|
247
|
+
data: { className, objectName },
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/** @type {import('eslint').JSRuleDefinition} */
|
|
257
|
+
var validServerActionsPathRule = {
|
|
258
|
+
meta: {
|
|
259
|
+
type: 'problem',
|
|
260
|
+
docs: {
|
|
261
|
+
description: 'enforce server actions are exported from file paths that match "app/**/_actions.ts" or "app/**/_actions/**/*.ts"',
|
|
262
|
+
url: 'https://github.com/friendsoftheweb/eslint-plugin#friendsofthewebvalid-server-actions-path',
|
|
263
|
+
},
|
|
264
|
+
schema: [],
|
|
265
|
+
messages: {
|
|
266
|
+
invalidPath: 'Server action files must be located in a directory named "_actions" or have the filename "_actions.ts"',
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
create(context) {
|
|
270
|
+
return {
|
|
271
|
+
ExpressionStatement(node) {
|
|
272
|
+
if (node.expression.type !== 'Literal' ||
|
|
273
|
+
node.expression.value !== 'use server') {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const basename = path.basename(context.filename);
|
|
277
|
+
const dirname = path.dirname(context.filename);
|
|
278
|
+
// Escape backslashes for RegExp (Windows paths)
|
|
279
|
+
const escapedSep = path.sep.replace('\\', '\\\\');
|
|
280
|
+
const isInActionsDir = new RegExp(`app(${escapedSep}.*)?${escapedSep}_actions`).test(dirname);
|
|
281
|
+
const isActionsFile = (dirname === 'app' || new RegExp(`app${escapedSep}`).test(dirname)) &&
|
|
282
|
+
/_actions\.(js|ts)$/.test(basename);
|
|
283
|
+
if (!isInActionsDir && !isActionsFile) {
|
|
284
|
+
context.report({
|
|
285
|
+
node,
|
|
286
|
+
messageId: 'invalidPath',
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
},
|
|
292
|
+
};
|
|
30
293
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
294
|
+
/** @type {import('eslint').ESLint.Plugin} */
|
|
295
|
+
const plugin = {
|
|
296
|
+
meta: {
|
|
297
|
+
name: packageJson.name,
|
|
298
|
+
version: packageJson.version,
|
|
299
|
+
},
|
|
300
|
+
configs: {},
|
|
34
301
|
rules: {
|
|
35
|
-
|
|
36
|
-
|
|
302
|
+
'ban-lodash-import': banLodashImport,
|
|
303
|
+
'css-module-name-matches': cssModuleNameMatchesRule,
|
|
304
|
+
'css-module-class-exists': cssModuleClassExistsRule,
|
|
305
|
+
'valid-server-actions-path': validServerActionsPathRule,
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
Object.assign(plugin.configs, {
|
|
309
|
+
'flat/recommended': [
|
|
310
|
+
{
|
|
311
|
+
plugins: {
|
|
312
|
+
friendsoftheweb: plugin,
|
|
313
|
+
},
|
|
314
|
+
rules: {
|
|
315
|
+
'friendsoftheweb/ban-lodash-import': 'error',
|
|
316
|
+
'friendsoftheweb/css-module-name-matches': 'error',
|
|
317
|
+
'friendsoftheweb/css-module-class-exists': 'error',
|
|
318
|
+
'friendsoftheweb/valid-server-actions-path': 'error',
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
'flat/migrate': [
|
|
323
|
+
{
|
|
324
|
+
plugins: {
|
|
325
|
+
friendsoftheweb: plugin,
|
|
326
|
+
},
|
|
327
|
+
rules: {
|
|
328
|
+
'friendsoftheweb/ban-lodash-import': 'warn',
|
|
329
|
+
'friendsoftheweb/css-module-name-matches': 'warn',
|
|
330
|
+
'friendsoftheweb/css-module-class-exists': 'warn',
|
|
331
|
+
'friendsoftheweb/valid-server-actions-path': 'warn',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
],
|
|
335
|
+
recommended: {
|
|
336
|
+
plugins: { friendsoftheweb: plugin },
|
|
337
|
+
rules: {
|
|
338
|
+
'friendsoftheweb/ban-lodash-import': 'error',
|
|
339
|
+
'friendsoftheweb/css-module-name-matches': 'error',
|
|
340
|
+
'friendsoftheweb/css-module-class-exists': 'error',
|
|
341
|
+
'friendsoftheweb/valid-server-actions-path': 'error',
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
migrate: {
|
|
345
|
+
plugins: { friendsoftheweb: plugin },
|
|
346
|
+
rules: {
|
|
347
|
+
'friendsoftheweb/ban-lodash-import': 'warn',
|
|
348
|
+
'friendsoftheweb/css-module-name-matches': 'warn',
|
|
349
|
+
'friendsoftheweb/css-module-class-exists': 'warn',
|
|
350
|
+
'friendsoftheweb/valid-server-actions-path': 'warn',
|
|
351
|
+
},
|
|
37
352
|
},
|
|
38
|
-
},
|
|
39
353
|
});
|
|
40
354
|
|
|
41
355
|
export { plugin as default };
|
package/dist/esm/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":[],"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,EAAE,wBAAwB;AACvD,IAAI,yBAAyB,EAAE,wBAAwB;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":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
meta: {
|
|
3
|
+
type: "problem";
|
|
4
|
+
fixable: "code";
|
|
5
|
+
docs: {
|
|
6
|
+
description: string;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
9
|
+
schema: any[];
|
|
10
|
+
messages: {
|
|
11
|
+
invalidImport: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
create(context: import("@eslint/core", { with: { "resolution-mode": "require" } }).RuleContext<{
|
|
15
|
+
LangOptions: import("eslint").Linter.LanguageOptions;
|
|
16
|
+
Code: import("eslint").SourceCode;
|
|
17
|
+
RuleOptions: unknown[];
|
|
18
|
+
Node: import("eslint").JSSyntaxElement;
|
|
19
|
+
MessageIds: string;
|
|
20
|
+
}>): {
|
|
21
|
+
ImportDeclaration(node: import("estree").ImportDeclaration & import("eslint").Rule.NodeParentExtension): void;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
meta: {
|
|
3
|
+
type: "problem";
|
|
4
|
+
docs: {
|
|
5
|
+
description: string;
|
|
6
|
+
url: string;
|
|
7
|
+
};
|
|
8
|
+
schema: any[];
|
|
9
|
+
messages: {
|
|
10
|
+
invalidPath: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
create(context: import("@eslint/core", { with: { "resolution-mode": "require" } }).RuleContext<{
|
|
14
|
+
LangOptions: import("eslint").Linter.LanguageOptions;
|
|
15
|
+
Code: import("eslint").SourceCode;
|
|
16
|
+
RuleOptions: unknown[];
|
|
17
|
+
Node: import("eslint").JSSyntaxElement;
|
|
18
|
+
MessageIds: string;
|
|
19
|
+
}>): {
|
|
20
|
+
ExpressionStatement(node: import("estree").ExpressionStatement & import("eslint").Rule.NodeParentExtension): void;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export default _default;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"repository": {
|
|
4
4
|
"url": "git+https://github.com/friendsoftheweb/eslint-plugin.git"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.2",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"packageManager": "yarn@4.12.0",
|
|
9
9
|
"main": "./dist/cjs/index.js",
|
|
@@ -21,26 +21,28 @@
|
|
|
21
21
|
"dist"
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
|
-
"test": "node test.mjs",
|
|
24
|
+
"test": "node test/index.mjs",
|
|
25
25
|
"types:check": "tsc --noEmit",
|
|
26
26
|
"lint": "eslint",
|
|
27
27
|
"format:check": "prettier --check .",
|
|
28
|
-
"build": "rm -rf dist && rollup --config rollup.config.
|
|
28
|
+
"build": "rm -rf dist && rollup --config rollup.config.mjs && tsc -p tsconfig.build.json"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
31
|
+
"@eslint/js": "^9.39.2",
|
|
32
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
33
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
34
|
+
"@types/node": "^22.19.3",
|
|
35
|
+
"eslint": "^9.39.2",
|
|
36
|
+
"eslint-plugin-eslint-plugin": "^7.3.0",
|
|
37
|
+
"prettier": "^3.7.4",
|
|
38
|
+
"rollup": "^4.55.1",
|
|
39
|
+
"sinon": "^21.0.1",
|
|
38
40
|
"tslib": "^2.8.1",
|
|
39
|
-
"typescript": "^5.
|
|
41
|
+
"typescript": "^5.9.3"
|
|
40
42
|
},
|
|
41
43
|
"dependencies": {
|
|
42
|
-
"postcss": "^8.5.
|
|
43
|
-
"postcss-selector-parser": "^7.1.
|
|
44
|
+
"postcss": "^8.5.6",
|
|
45
|
+
"postcss-selector-parser": "^7.1.1"
|
|
44
46
|
},
|
|
45
47
|
"peerDependencies": {
|
|
46
48
|
"eslint": ">=9.0.0"
|