eslint-plugin-raflint 1.2.11 → 1.3.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 +15 -1
- package/TESTING.md +18 -0
- package/dist/bundle.cjs +48 -0
- package/eslint.config.js +284 -0
- package/eslinttest.config.js +13 -0
- package/index.js +46 -0
- package/package.json +22 -18
- package/rules/noPathJoin.js +48 -0
- package/test/noConditionalObjectSpread.test.js +6 -4
- package/test/noPathJoin.test.js +58 -0
- package/testExample.js +22 -0
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# README
|
|
2
2
|
|
|
3
|
-
Ce plugin eslint permet de détecter
|
|
3
|
+
Ce plugin eslint permet de détecter:
|
|
4
|
+
|
|
5
|
+
## no-conditional-object-spread
|
|
6
|
+
|
|
7
|
+
Les écritures du style :
|
|
4
8
|
|
|
5
9
|
const obj = {
|
|
6
10
|
...(condition ? { prop: 'value' } : {}),
|
|
@@ -15,3 +19,13 @@ qui devrait être écrites comme ça:
|
|
|
15
19
|
const condition = true;
|
|
16
20
|
const obj = {};
|
|
17
21
|
if (condition) obj.prop = value;
|
|
22
|
+
|
|
23
|
+
## no-path-join
|
|
24
|
+
|
|
25
|
+
Les utilisations de `path.join()` avec deux arguments qui peuvent être remplacées par des template strings:
|
|
26
|
+
|
|
27
|
+
const filePath = path.join(directory, filename);
|
|
28
|
+
|
|
29
|
+
qui devrait être écrites comme ça:
|
|
30
|
+
|
|
31
|
+
const filePath = `${directory}/${filename}`;
|
package/TESTING.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Comment tester la règle no-path-join
|
|
2
|
+
## Test manuel avec le fichier d'exemple
|
|
3
|
+
|
|
4
|
+
Un fichier d'exemple `testExample.js` a été créé pour démontrer le fonctionnement de la règle. Pour tester manuellement:
|
|
5
|
+
|
|
6
|
+
1. Vérifier que la règle détecte les problèmes:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx eslint -c eslinttest.config.js testExample.js
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Vous devriez voir des erreurs pour les lignes contenant `path.join(directory, filename)` et `path.join(process.cwd(), 'file.txt')`.
|
|
13
|
+
|
|
14
|
+
2. Vérifier que la règle corrige automatiquement le code:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx eslint -c eslinttest.config.js testExample.js --fix
|
|
18
|
+
```
|
package/dist/bundle.cjs
CHANGED
|
@@ -14,5 +14,53 @@ module.exports = {
|
|
|
14
14
|
};
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
|
+
'no-path-join': {
|
|
18
|
+
meta: {
|
|
19
|
+
type: 'suggestion',
|
|
20
|
+
docs: {
|
|
21
|
+
description: 'Disallow path.join(a, b) in favor of template strings',
|
|
22
|
+
category: 'Stylistic Issues',
|
|
23
|
+
recommended: true,
|
|
24
|
+
},
|
|
25
|
+
fixable: 'code',
|
|
26
|
+
schema: [],
|
|
27
|
+
},
|
|
28
|
+
create(context) {
|
|
29
|
+
return {
|
|
30
|
+
CallExpression(node) {
|
|
31
|
+
// Vérifier si c'est un appel à path.join
|
|
32
|
+
if (
|
|
33
|
+
node.callee.type === 'MemberExpression' &&
|
|
34
|
+
node.callee.object.name === 'path' &&
|
|
35
|
+
node.callee.property.name === 'join' &&
|
|
36
|
+
// Uniquement pour les cas avec exactement 2 arguments
|
|
37
|
+
node.arguments.length === 2
|
|
38
|
+
) {
|
|
39
|
+
const sourceCode = context.getSourceCode();
|
|
40
|
+
const arg1 = sourceCode.getText(node.arguments[0]);
|
|
41
|
+
const arg2 = sourceCode.getText(node.arguments[1]);
|
|
42
|
+
|
|
43
|
+
// Vérifier si le second argument est une chaîne littérale
|
|
44
|
+
let replacement;
|
|
45
|
+
if (node.arguments[1].type === 'Literal' && typeof node.arguments[1].value === 'string') {
|
|
46
|
+
// Si c'est une chaîne littérale, l'inclure directement sans ${}
|
|
47
|
+
replacement = `\`\${${arg1}}/${node.arguments[1].value}\``;
|
|
48
|
+
} else {
|
|
49
|
+
// Sinon, utiliser le format standard avec ${}
|
|
50
|
+
replacement = `\`\${${arg1}}/\${${arg2}}\``;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
context.report({
|
|
54
|
+
node,
|
|
55
|
+
message: 'Utilisez des template strings au lieu de path.join() pour la concaténation de chemins simples',
|
|
56
|
+
fix(fixer) {
|
|
57
|
+
return fixer.replaceText(node, replacement);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
},
|
|
17
65
|
},
|
|
18
66
|
};
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import sonarjs from 'eslint-plugin-sonarjs';
|
|
2
|
+
import unicorn from 'eslint-plugin-unicorn';
|
|
3
|
+
import promise from 'eslint-plugin-promise';
|
|
4
|
+
import n from 'eslint-plugin-n';
|
|
5
|
+
import raflint from 'eslint-plugin-raflint';
|
|
6
|
+
import pluginimport from 'eslint-plugin-import';
|
|
7
|
+
import babelParser from '@babel/eslint-parser';
|
|
8
|
+
import js from '@eslint/js';
|
|
9
|
+
import globals from 'globals';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export default [
|
|
14
|
+
// eslint:recommended,
|
|
15
|
+
js.configs.recommended,
|
|
16
|
+
|
|
17
|
+
// unicorn
|
|
18
|
+
unicorn.configs['flat/recommended'],
|
|
19
|
+
|
|
20
|
+
// n
|
|
21
|
+
n.configs['flat/recommended'],
|
|
22
|
+
|
|
23
|
+
// sonarjs
|
|
24
|
+
sonarjs.configs.recommended,
|
|
25
|
+
|
|
26
|
+
// promise
|
|
27
|
+
promise.configs['flat/recommended'],
|
|
28
|
+
|
|
29
|
+
// plugin:import/recommended,
|
|
30
|
+
pluginimport.flatConfigs.recommended,
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
ignores: [
|
|
34
|
+
"node_modules/",
|
|
35
|
+
"web/",
|
|
36
|
+
"public/",
|
|
37
|
+
"coverage/",
|
|
38
|
+
"data/",
|
|
39
|
+
"vendor/",
|
|
40
|
+
"cypress/",
|
|
41
|
+
"react/",
|
|
42
|
+
"js/",
|
|
43
|
+
"assets/",
|
|
44
|
+
"**/old/",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
languageOptions: {
|
|
49
|
+
globals: {
|
|
50
|
+
...globals.browser,
|
|
51
|
+
...globals.node,
|
|
52
|
+
...globals.mocha,
|
|
53
|
+
},
|
|
54
|
+
parser: babelParser,
|
|
55
|
+
parserOptions: {
|
|
56
|
+
ecmaVersion: "latest",
|
|
57
|
+
sourceType: "module",
|
|
58
|
+
requireConfigFile: false,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
plugins: {
|
|
62
|
+
raflint,
|
|
63
|
+
},
|
|
64
|
+
rules: {
|
|
65
|
+
"sonarjs/no-empty-function": 0,
|
|
66
|
+
"sonarjs/no-unused-expressions": 0,
|
|
67
|
+
"sonarjs/no-unsafe-unzip": 0,
|
|
68
|
+
"sonarjs/os-command": 0,
|
|
69
|
+
"sonarjs/cors": 0,
|
|
70
|
+
"sonarjs/publicly-writable-directories": 0,
|
|
71
|
+
"sonarjs/file-permissions": 0,
|
|
72
|
+
"sonarjs/no-empty-test-file": 0,
|
|
73
|
+
"import/no-named-as-default-member": 0,
|
|
74
|
+
"sonarjs/regex-complexity": 0,
|
|
75
|
+
"sonarjs/no-clear-text-protocols": 0,
|
|
76
|
+
"sonarjs/no-infinite-loop": 0,
|
|
77
|
+
"sonarjs/no-hardcoded-ip": 0,
|
|
78
|
+
"sonarjs/pluginRules-of-hooks": 0,
|
|
79
|
+
"sonarjs/sonar-no-fallthrough": 0,
|
|
80
|
+
"sonarjs/no-ignored-exceptions": 0,
|
|
81
|
+
"sonarjs/slow-regex": 0,
|
|
82
|
+
"sonarjs/concise-regex": 0,
|
|
83
|
+
"sonarjs/hashing": 0,
|
|
84
|
+
"sonarjs/no-dead-store": 0,
|
|
85
|
+
"sonarjs/no-unused-vars": 0,
|
|
86
|
+
"sonarjs/no-hardcoded-passwords": 0,
|
|
87
|
+
"sonarjs/no-hardcoded-secrets": 0,
|
|
88
|
+
"sonarjs/unnecessary-character-escapes": 0,
|
|
89
|
+
"sonarjs/pseudo-random": 0,
|
|
90
|
+
"sonarjs/no-os-command-from-path": 0,
|
|
91
|
+
"sonarjs/anchor-precedence": 0,
|
|
92
|
+
"sonarjs/no-nested-functions": 0,
|
|
93
|
+
"sonarjs/new-cap": 0,
|
|
94
|
+
"sonarjs/sql-queries": 0,
|
|
95
|
+
"sonarjs/content-length": 0,
|
|
96
|
+
"sonarjs/no-commented-code": 0,
|
|
97
|
+
"raflint/no-conditional-object-spread": ["error"],
|
|
98
|
+
"raflint/no-path-join": ["error"],
|
|
99
|
+
// "import/no-named-as-default-member": 0,
|
|
100
|
+
"unicorn/prefer-event-target": 0,
|
|
101
|
+
"unicorn/prefer-structured-clone": 0,
|
|
102
|
+
"unicorn/prefer-string-raw": 0,
|
|
103
|
+
"unicorn/no-anonymous-default-export": 0,
|
|
104
|
+
"unicorn/better-regex": 0,
|
|
105
|
+
"unicorn/catch-error-name": 0,
|
|
106
|
+
"unicorn/consistent-function-scoping": 0,
|
|
107
|
+
"unicorn/expiring-todo-comments": 0,
|
|
108
|
+
"unicorn/explicit-length-check": 0,
|
|
109
|
+
"unicorn/import-style": 0,
|
|
110
|
+
"unicorn/no-array-for-each": 0,
|
|
111
|
+
"unicorn/prefer-single-call": 0,
|
|
112
|
+
"unicorn/no-array-reduce": 0,
|
|
113
|
+
"unicorn/no-lonely-if": 0,
|
|
114
|
+
"unicorn/no-negated-condition": 0,
|
|
115
|
+
"unicorn/no-null": 0,
|
|
116
|
+
"unicorn/no-process-exit": 0,
|
|
117
|
+
"unicorn/no-this-assignment": 0,
|
|
118
|
+
"unicorn/no-unnecessary-await": 0,
|
|
119
|
+
"unicorn/no-unused-properties": 0,
|
|
120
|
+
"unicorn/prefer-code-point": 0,
|
|
121
|
+
"unicorn/prefer-default-parameters": 0,
|
|
122
|
+
"unicorn/prefer-export-from": 0,
|
|
123
|
+
"unicorn/prefer-native-coercion-functions": 0,
|
|
124
|
+
"unicorn/prefer-number-properties": 0,
|
|
125
|
+
"unicorn/prefer-set-has": 0,
|
|
126
|
+
"unicorn/prefer-set-size": 0,
|
|
127
|
+
"unicorn/prefer-spread": 0,
|
|
128
|
+
"unicorn/prefer-string-replace-all": 0,
|
|
129
|
+
"unicorn/prefer-string-slice": 0,
|
|
130
|
+
"unicorn/prefer-switch": 0,
|
|
131
|
+
"unicorn/prefer-ternary": 0,
|
|
132
|
+
"unicorn/prefer-top-level-await": 0,
|
|
133
|
+
"unicorn/prevent-abbreviations": 0,
|
|
134
|
+
"unicorn/relative-url-style": 0,
|
|
135
|
+
"unicorn/switch-case-braces": 0,
|
|
136
|
+
"unicorn/template-indent": 0,
|
|
137
|
+
"unicorn/text-encoding-identifier-case": 0,
|
|
138
|
+
"unicorn/prefer-regexp-test": 0,
|
|
139
|
+
"unicorn/prefer-optional-catch-binding": 0,
|
|
140
|
+
"unicorn/filename-case": [
|
|
141
|
+
"error",
|
|
142
|
+
{
|
|
143
|
+
"case": "camelCase"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"sonarjs/cognitive-complexity": 0,
|
|
147
|
+
"sonarjs/no-nested-template-literals": 0,
|
|
148
|
+
"sonarjs/no-collapsible-if": 0,
|
|
149
|
+
"sonarjs/no-duplicate-string": 0,
|
|
150
|
+
"sonarjs/prefer-immediate-return": 0,
|
|
151
|
+
"sonarjs/no-identical-functions": 0,
|
|
152
|
+
"sonarjs/prefer-object-literal": 0,
|
|
153
|
+
"sonarjs/prefer-single-boolean-return": 0,
|
|
154
|
+
"n/no-unpublished-import": 0,
|
|
155
|
+
"n/no-unsupported-features/es-syntax": 0,
|
|
156
|
+
"n/no-missing-import": 0,
|
|
157
|
+
"n/no-process-exit": 0,
|
|
158
|
+
|
|
159
|
+
// si on l'active ça pose pb dans check / automerge
|
|
160
|
+
"n/shebang": 0,
|
|
161
|
+
|
|
162
|
+
"one-var-declaration-per-line": ["error", "always"],
|
|
163
|
+
"one-var": ["error", "never"],
|
|
164
|
+
"no-unused-expressions": "error",
|
|
165
|
+
"no-nested-ternary": "error",
|
|
166
|
+
"no-use-before-define": [
|
|
167
|
+
"error",
|
|
168
|
+
{
|
|
169
|
+
"functions": false,
|
|
170
|
+
"classes": false,
|
|
171
|
+
"variables": true,
|
|
172
|
+
"allowNamedExports": false
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
"no-new-native-nonconstructor": "error",
|
|
176
|
+
"no-empty-static-block": "error",
|
|
177
|
+
"symbol-description": "error",
|
|
178
|
+
"require-yield": "error",
|
|
179
|
+
"prefer-spread": "error",
|
|
180
|
+
"prefer-rest-params": "error",
|
|
181
|
+
"prefer-object-spread": "error",
|
|
182
|
+
"prefer-object-has-own": "error",
|
|
183
|
+
"prefer-numeric-literals": "error",
|
|
184
|
+
"prefer-exponentiation-operator": "error",
|
|
185
|
+
"operator-assignment": "error",
|
|
186
|
+
"no-useless-rename": "error",
|
|
187
|
+
"no-useless-constructor": "error",
|
|
188
|
+
"no-useless-computed-key": "error",
|
|
189
|
+
"no-unused-labels": "error",
|
|
190
|
+
"no-script-url": "error",
|
|
191
|
+
"no-new-object": "error",
|
|
192
|
+
"no-multi-assign": "error",
|
|
193
|
+
"no-loop-func": "error",
|
|
194
|
+
"no-inline-comments": "error",
|
|
195
|
+
"no-implicit-coercion": "error",
|
|
196
|
+
"no-extra-boolean-cast": "error",
|
|
197
|
+
"no-confusing-arrow": "error",
|
|
198
|
+
"no-case-declarations": "error",
|
|
199
|
+
"no-bitwise": "error",
|
|
200
|
+
"no-array-constructor": "error",
|
|
201
|
+
"no-alert": "error",
|
|
202
|
+
"logical-assignment-operators": "error",
|
|
203
|
+
"grouped-accessor-pairs": "error",
|
|
204
|
+
"func-name-matching": "error",
|
|
205
|
+
"dot-notation": "error",
|
|
206
|
+
"consistent-this": ["error", "self"],
|
|
207
|
+
"accessor-pairs": "error",
|
|
208
|
+
"no-unused-private-class-members": "error",
|
|
209
|
+
"no-promise-executor-return": "error",
|
|
210
|
+
"no-duplicate-imports": "error",
|
|
211
|
+
"no-constant-binary-expression": "error",
|
|
212
|
+
"no-undef-init": "error",
|
|
213
|
+
"no-label-var": "error",
|
|
214
|
+
"init-declarations": ["error", "always"],
|
|
215
|
+
"wrap-iife": ["error", "inside"],
|
|
216
|
+
"yoda": "error",
|
|
217
|
+
"vars-on-top": "error",
|
|
218
|
+
"radix": ["error", "as-needed"],
|
|
219
|
+
"prefer-regex-literals": "error",
|
|
220
|
+
"prefer-promise-reject-errors": "error",
|
|
221
|
+
"no-warning-comments": "error",
|
|
222
|
+
"no-void": "error",
|
|
223
|
+
"no-useless-return": "error",
|
|
224
|
+
"no-useless-concat": "error",
|
|
225
|
+
"no-useless-call": "error",
|
|
226
|
+
"no-throw-literal": "error",
|
|
227
|
+
"no-sequences": "error",
|
|
228
|
+
"no-self-compare": "error",
|
|
229
|
+
"no-return-assign": "error",
|
|
230
|
+
"no-proto": "error",
|
|
231
|
+
"no-octal-escape": "error",
|
|
232
|
+
"no-nonoctal-decimal-escape": "error",
|
|
233
|
+
"no-new-wrappers": "error",
|
|
234
|
+
"no-new-func": "error",
|
|
235
|
+
"no-new": "error",
|
|
236
|
+
"no-multi-str": "error",
|
|
237
|
+
"no-multi-spaces": "error",
|
|
238
|
+
"no-lone-blocks": "error",
|
|
239
|
+
"no-labels": "error",
|
|
240
|
+
"no-iterator": "error",
|
|
241
|
+
"no-empty-function": "error",
|
|
242
|
+
"block-scoped-var": "error",
|
|
243
|
+
"prefer-arrow-callback": "error",
|
|
244
|
+
"no-implied-eval": "error",
|
|
245
|
+
"no-implicit-globals": "error",
|
|
246
|
+
"no-floating-decimal": "error",
|
|
247
|
+
"no-extra-label": "error",
|
|
248
|
+
"no-extra-bind": "error",
|
|
249
|
+
"no-extend-native": [
|
|
250
|
+
"error",
|
|
251
|
+
{
|
|
252
|
+
"exceptions": ["Object"]
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
"no-eval": "error",
|
|
256
|
+
"no-constant-condition": ["error", { "checkLoops": false }],
|
|
257
|
+
"no-eq-null": "error",
|
|
258
|
+
"no-else-return": "error",
|
|
259
|
+
"no-unused-vars": 0,
|
|
260
|
+
"no-console": 0,
|
|
261
|
+
"no-empty": 0,
|
|
262
|
+
"no-redeclare": 0,
|
|
263
|
+
"no-useless-escape": 0,
|
|
264
|
+
"no-var": "error",
|
|
265
|
+
"object-shorthand": ["error", "properties"],
|
|
266
|
+
"prefer-template": "error",
|
|
267
|
+
"no-div-regex": "error",
|
|
268
|
+
"no-constructor-return": "error",
|
|
269
|
+
"no-caller": "error",
|
|
270
|
+
"max-classes-per-file": "error",
|
|
271
|
+
"default-param-last": "error",
|
|
272
|
+
"default-case-last": "error",
|
|
273
|
+
"default-case": "error",
|
|
274
|
+
"array-callback-return": "error",
|
|
275
|
+
"no-unsafe-optional-chaining": "error",
|
|
276
|
+
"no-unreachable-loop": "error",
|
|
277
|
+
"no-template-curly-in-string": "error",
|
|
278
|
+
"no-loss-of-precision": "error",
|
|
279
|
+
"no-inner-declarations": 0,
|
|
280
|
+
"no-process-exit": 0,
|
|
281
|
+
"prefer-const": ["error", { "destructuring": "all" }]
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
];
|
package/index.js
CHANGED
|
@@ -1,7 +1,53 @@
|
|
|
1
1
|
import noConditionalObjectSpread from './rules/noConditionalObjectSpread.js';
|
|
2
|
+
import noPathJoin from './rules/noPathJoin.js';
|
|
2
3
|
|
|
3
4
|
export default {
|
|
4
5
|
rules: {
|
|
5
6
|
'no-conditional-object-spread': noConditionalObjectSpread,
|
|
7
|
+
'no-path-join': noPathJoin,
|
|
6
8
|
},
|
|
7
9
|
};
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
import fs from 'node:fs';
|
|
16
|
+
const { name, version } = JSON.parse(await fs.promises.readFile(`${__dirname}/package.json`));
|
|
17
|
+
|
|
18
|
+
import noConditionalObjectSpread from './rules/noConditionalObjectSpread.js';
|
|
19
|
+
import noPathJoin from './rules/noPathJoin.js';
|
|
20
|
+
|
|
21
|
+
const rules = {
|
|
22
|
+
'no-conditional-object-spread': noConditionalObjectSpread,
|
|
23
|
+
'no-path-join': noPathJoin,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
meta: {
|
|
28
|
+
name,
|
|
29
|
+
version,
|
|
30
|
+
},
|
|
31
|
+
rules,
|
|
32
|
+
configs: {
|
|
33
|
+
'flat/recommended': {
|
|
34
|
+
plugins: {
|
|
35
|
+
raflint: {
|
|
36
|
+
meta: {
|
|
37
|
+
name,
|
|
38
|
+
version,
|
|
39
|
+
},
|
|
40
|
+
rules: {
|
|
41
|
+
'raflint/no-conditional-object-spread': "error",
|
|
42
|
+
'raflint/no-path-join': "error"
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
rules: {
|
|
47
|
+
'raflint/no-conditional-object-spread': "error",
|
|
48
|
+
'raflint/no-path-join': "error"
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-raflint",
|
|
3
|
-
"version": "1.2
|
|
3
|
+
"version": "1.3.2",
|
|
4
|
+
"private": false,
|
|
4
5
|
"description": "",
|
|
5
6
|
"keywords": [],
|
|
6
7
|
"repository": {
|
|
@@ -23,26 +24,29 @@
|
|
|
23
24
|
"test": "SILENT=1 mocha --timeout 15000 {lib,test}/**/*.test.js"
|
|
24
25
|
},
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"@babel/eslint-parser": "^7.
|
|
27
|
-
"
|
|
28
|
-
"eslint": "^
|
|
29
|
-
"eslint-plugin-
|
|
30
|
-
"eslint-plugin-
|
|
31
|
-
"eslint-plugin-
|
|
32
|
-
"eslint-plugin-sonarjs": "^1.0.0",
|
|
33
|
-
"eslint-plugin-unicorn": "^52.0.0",
|
|
34
|
-
"html-validate": "^8.18.2",
|
|
35
|
-
"husky": "^9.0.11",
|
|
36
|
-
"jest": "^29.7.0",
|
|
37
|
-
"lint-staged": "^15.2.2",
|
|
38
|
-
"mocha": "^10.4.0",
|
|
39
|
-
"prettier": "^3.2.5"
|
|
27
|
+
"@babel/eslint-parser": "^7.27.1",
|
|
28
|
+
"@eslint/js": "^9.26.0",
|
|
29
|
+
"eslint": "^9.26.0",
|
|
30
|
+
"eslint-plugin-n": "^17.17.0",
|
|
31
|
+
"eslint-plugin-sonarjs": "^3.0.2",
|
|
32
|
+
"eslint-plugin-unicorn": "^59.0.0"
|
|
40
33
|
},
|
|
41
34
|
"devDependencies": {
|
|
42
|
-
"
|
|
43
|
-
"
|
|
35
|
+
"@stoplight/spectral-cli": "^6.15.0",
|
|
36
|
+
"c8": "^10.1.3",
|
|
37
|
+
"eslint-plugin-import": "^2.31.0",
|
|
38
|
+
"eslint-plugin-promise": "^7.2.1",
|
|
39
|
+
"eslint-plugin-raflint": "^1.3.0",
|
|
40
|
+
"globals": "^16.0.0",
|
|
41
|
+
"html-validate": "^9.5.3",
|
|
42
|
+
"husky": "^9.1.7",
|
|
43
|
+
"jest": "^29.7.0",
|
|
44
|
+
"lint-staged": "^15.5.1",
|
|
45
|
+
"markdownlint": "^0.38.0",
|
|
46
|
+
"mocha": "^11.2.2",
|
|
47
|
+
"prettier": "^3.5.3"
|
|
44
48
|
},
|
|
45
49
|
"engines": {
|
|
46
|
-
"node": ">=
|
|
50
|
+
"node": ">=21.0.0"
|
|
47
51
|
}
|
|
48
52
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
meta: {
|
|
3
|
+
type: 'suggestion',
|
|
4
|
+
docs: {
|
|
5
|
+
description: 'Disallow path.join(a, b) in favor of template strings',
|
|
6
|
+
category: 'Stylistic Issues',
|
|
7
|
+
recommended: true,
|
|
8
|
+
},
|
|
9
|
+
fixable: 'code',
|
|
10
|
+
schema: [],
|
|
11
|
+
},
|
|
12
|
+
create(context) {
|
|
13
|
+
return {
|
|
14
|
+
CallExpression(node) {
|
|
15
|
+
// Vérifier si c'est un appel à path.join
|
|
16
|
+
if (
|
|
17
|
+
node.callee.type === 'MemberExpression' &&
|
|
18
|
+
node.callee.object.name === 'path' &&
|
|
19
|
+
node.callee.property.name === 'join' &&
|
|
20
|
+
// Uniquement pour les cas avec exactement 2 arguments
|
|
21
|
+
node.arguments.length === 2
|
|
22
|
+
) {
|
|
23
|
+
const sourceCode = context.getSourceCode();
|
|
24
|
+
const arg1 = sourceCode.getText(node.arguments[0]);
|
|
25
|
+
const arg2 = sourceCode.getText(node.arguments[1]);
|
|
26
|
+
|
|
27
|
+
// Vérifier si le second argument est une chaîne littérale
|
|
28
|
+
let replacement;
|
|
29
|
+
if (node.arguments[1].type === 'Literal' && typeof node.arguments[1].value === 'string') {
|
|
30
|
+
// Si c'est une chaîne littérale, l'inclure directement sans ${}
|
|
31
|
+
replacement = `\`\${${arg1}}/${node.arguments[1].value}\``;
|
|
32
|
+
} else {
|
|
33
|
+
// Sinon, utiliser le format standard avec ${}
|
|
34
|
+
replacement = `\`\${${arg1}}/\${${arg2}}\``;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
context.report({
|
|
38
|
+
node,
|
|
39
|
+
message: 'Utilisez des template strings au lieu de path.join() pour la concaténation de chemins simples',
|
|
40
|
+
fix(fixer) {
|
|
41
|
+
return fixer.replaceText(node, replacement);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { RuleTester } from 'eslint';
|
|
2
2
|
import noConditionalObjectSpread from '../rules/noConditionalObjectSpread.js';
|
|
3
|
-
import path
|
|
3
|
+
import path from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
|
|
7
7
|
const ruleTester = new RuleTester({
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
languageOptions: {
|
|
9
|
+
parser: await import('@babel/eslint-parser'),
|
|
10
10
|
ecmaVersion: 'latest',
|
|
11
11
|
sourceType: 'module',
|
|
12
|
-
|
|
12
|
+
parserOptions: {
|
|
13
|
+
requireConfigFile: false,
|
|
14
|
+
},
|
|
13
15
|
},
|
|
14
16
|
});
|
|
15
17
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { RuleTester } from 'eslint';
|
|
2
|
+
import noPathJoin from '../rules/noPathJoin.js';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
|
|
7
|
+
const ruleTester = new RuleTester({
|
|
8
|
+
languageOptions: {
|
|
9
|
+
parser: await import('@babel/eslint-parser'),
|
|
10
|
+
ecmaVersion: 'latest',
|
|
11
|
+
sourceType: 'module',
|
|
12
|
+
parserOptions: {
|
|
13
|
+
requireConfigFile: false,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
ruleTester.run('no-path-join', noPathJoin, {
|
|
19
|
+
valid: [
|
|
20
|
+
{
|
|
21
|
+
code: `
|
|
22
|
+
const filePath = \`\${directory}/\${filename}\`;
|
|
23
|
+
`,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
// Cas avec plus de 2 arguments (non concerné par la règle)
|
|
27
|
+
code: `
|
|
28
|
+
const filePath = path.join(root, directory, filename);
|
|
29
|
+
`,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
// Cas avec un autre objet que path
|
|
33
|
+
code: `
|
|
34
|
+
const result = utils.join(a, b);
|
|
35
|
+
`,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
invalid: [
|
|
39
|
+
{
|
|
40
|
+
code: `
|
|
41
|
+
const filePath = path.join(directory, filename);
|
|
42
|
+
`,
|
|
43
|
+
errors: [{ message: 'Utilisez des template strings au lieu de path.join() pour la concaténation de chemins simples' }],
|
|
44
|
+
output: `
|
|
45
|
+
const filePath = \`\${directory}/\${filename}\`;
|
|
46
|
+
`,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
code: `
|
|
50
|
+
const filePath = path.join(process.cwd(), 'file.txt');
|
|
51
|
+
`,
|
|
52
|
+
errors: [{ message: 'Utilisez des template strings au lieu de path.join() pour la concaténation de chemins simples' }],
|
|
53
|
+
output: `
|
|
54
|
+
const filePath = \`\${process.cwd()}/file.txt\`;
|
|
55
|
+
`,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
});
|
package/testExample.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Exemple de code utilisant path.join() qui sera détecté par notre règle
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
// Définition des variables pour éviter les erreurs ESLint
|
|
5
|
+
const directory = '/home/user';
|
|
6
|
+
const filename = 'file.txt';
|
|
7
|
+
const root = '/';
|
|
8
|
+
|
|
9
|
+
// Ce code sera détecté et corrigé par notre règle
|
|
10
|
+
const filePath1 = path.join(directory, filename);
|
|
11
|
+
|
|
12
|
+
// Ce code sera détecté et corrigé par notre règle
|
|
13
|
+
const filePath2 = path.join(process.cwd(), 'file.txt');
|
|
14
|
+
|
|
15
|
+
// Ce code ne sera pas détecté car il a plus de 2 arguments
|
|
16
|
+
const filePath3 = path.join(root, directory, filename);
|
|
17
|
+
|
|
18
|
+
// Ce code est déjà au format recommandé
|
|
19
|
+
const filePath4 = `${directory}/${filename}`;
|
|
20
|
+
|
|
21
|
+
// Pour éviter les erreurs "unused variable"
|
|
22
|
+
console.log(filePath1, filePath2, filePath3, filePath4);
|