@alveole/eslint-config 0.23.4 → 0.24.1
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/index.js +4 -65
- package/package.json +1 -1
- package/rules/_shared.js +121 -0
package/index.js
CHANGED
|
@@ -4,68 +4,7 @@ const sharedRules = require('./rules/_shared');
|
|
|
4
4
|
const styleRules = require('./rules/styles');
|
|
5
5
|
const serviceRules = require('./rules/services');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
files: ['**/*.{ts,tsx}'],
|
|
14
|
-
rules: {
|
|
15
|
-
'no-redeclare': 'off',
|
|
16
|
-
'@typescript-eslint/no-redeclare': ['error', { ignoreDeclarationMerge: true }],
|
|
17
|
-
'no-restricted-properties': [
|
|
18
|
-
'error',
|
|
19
|
-
{
|
|
20
|
-
object: 'window',
|
|
21
|
-
property: 'open',
|
|
22
|
-
message: 'N’utilisez pas window.open. Utilisez Linking.openURL (expo) à la place.',
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
'no-unused-vars': 'off',
|
|
26
|
-
'@typescript-eslint/no-unused-vars': [
|
|
27
|
-
'error',
|
|
28
|
-
{
|
|
29
|
-
argsIgnorePattern: '^_',
|
|
30
|
-
varsIgnorePattern: '^_',
|
|
31
|
-
caughtErrorsIgnorePattern: '^_',
|
|
32
|
-
ignoreRestSiblings: true,
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
files: ['**/*.styles.ts'],
|
|
39
|
-
rules: {
|
|
40
|
-
'no-restricted-syntax': [
|
|
41
|
-
'error',
|
|
42
|
-
{
|
|
43
|
-
selector: "Property[key.name='transition'], Property[key.value='transition']",
|
|
44
|
-
message:
|
|
45
|
-
'N’utilisez pas la propriété CSS transition. Utilisez transitionBehavior, transitionDelay, transitionDuration, transitionProperty ou transitionTimingFunction à la place.',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
selector:
|
|
49
|
-
"Property[key.name='padding'] > Literal[value=/\\s+/], Property[key.value='padding'] > Literal[value=/\\s+/]",
|
|
50
|
-
message:
|
|
51
|
-
'N’utilisez pas la forme raccourcie padding avec plusieurs valeurs. Utilisez paddingTop, paddingBottom, paddingLeft et paddingRight à la place.',
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
selector: "Property[key.name='border'], Property[key.value='border']",
|
|
55
|
-
message:
|
|
56
|
-
'N’utilisez pas la propriété raccourcie border. Utilisez borderColor, borderWidth, borderStyle, etc. à la place.',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
selector: "Property[key.name='background'], Property[key.value='background']",
|
|
60
|
-
message: 'N’utilisez pas la propriété raccourcie background. Utilisez backgroundColor, etc. à la place.',
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
files: ['**/services/**/*.{ts,tsx}'],
|
|
67
|
-
rules: {
|
|
68
|
-
'@typescript-eslint/no-redeclare': 'off',
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
]);
|
|
7
|
+
/** @type {import('eslint').Linter.Config[]} */
|
|
8
|
+
const config = defineConfig([expoConfig, { ignores: ['dist/**'] }, sharedRules, styleRules, serviceRules]);
|
|
9
|
+
|
|
10
|
+
module.exports = config;
|
package/package.json
CHANGED
package/rules/_shared.js
CHANGED
|
@@ -1,9 +1,130 @@
|
|
|
1
|
+
const flashListPlugin = {
|
|
2
|
+
rules: {
|
|
3
|
+
'prefer-flash-list': {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'suggestion',
|
|
6
|
+
fixable: 'code',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Interdit FlatList (react-native) et impose FlashList (@shopify/flash-list).',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
preferFlashList:
|
|
12
|
+
'N’utilisez pas FlatList depuis react-native. Utilisez FlashList depuis @shopify/flash-list.',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
create(context) {
|
|
17
|
+
const sourceCode = context.sourceCode;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
ImportDeclaration(node) {
|
|
21
|
+
if (node.source.value !== 'react-native') {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const flatListSpecifier = node.specifiers.find(
|
|
26
|
+
specifier =>
|
|
27
|
+
specifier.type === 'ImportSpecifier' &&
|
|
28
|
+
specifier.imported &&
|
|
29
|
+
specifier.imported.type === 'Identifier' &&
|
|
30
|
+
specifier.imported.name === 'FlatList',
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
if (!flatListSpecifier) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
context.report({
|
|
38
|
+
node: flatListSpecifier,
|
|
39
|
+
messageId: 'preferFlashList',
|
|
40
|
+
fix(fixer) {
|
|
41
|
+
const program = node.parent;
|
|
42
|
+
if (!program || program.type !== 'Program') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const importDeclarations = program.body.filter(statement => statement.type === 'ImportDeclaration');
|
|
47
|
+
const flashListImport = importDeclarations.find(
|
|
48
|
+
statement => statement.source.value === '@shopify/flash-list',
|
|
49
|
+
);
|
|
50
|
+
const hasFlashListAlready =
|
|
51
|
+
!!flashListImport &&
|
|
52
|
+
flashListImport.specifiers.some(
|
|
53
|
+
specifier =>
|
|
54
|
+
specifier.type === 'ImportSpecifier' &&
|
|
55
|
+
specifier.imported &&
|
|
56
|
+
specifier.imported.type === 'Identifier' &&
|
|
57
|
+
specifier.imported.name === 'FlashList',
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const fixes = [];
|
|
61
|
+
|
|
62
|
+
if (node.specifiers.length === 1) {
|
|
63
|
+
if (hasFlashListAlready) {
|
|
64
|
+
fixes.push(fixer.remove(node));
|
|
65
|
+
} else {
|
|
66
|
+
fixes.push(fixer.replaceText(node, "import { FlashList } from '@shopify/flash-list';"));
|
|
67
|
+
}
|
|
68
|
+
return fixes;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let [start, end] = flatListSpecifier.range;
|
|
72
|
+
const tokenBefore = sourceCode.getTokenBefore(flatListSpecifier);
|
|
73
|
+
const tokenAfter = sourceCode.getTokenAfter(flatListSpecifier);
|
|
74
|
+
|
|
75
|
+
if (tokenAfter && tokenAfter.value === ',') {
|
|
76
|
+
end = tokenAfter.range[1];
|
|
77
|
+
} else if (tokenBefore && tokenBefore.value === ',') {
|
|
78
|
+
start = tokenBefore.range[0];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fixes.push(fixer.removeRange([start, end]));
|
|
82
|
+
|
|
83
|
+
if (!hasFlashListAlready) {
|
|
84
|
+
if (flashListImport) {
|
|
85
|
+
const hasNamedSpecifiers = flashListImport.specifiers.some(
|
|
86
|
+
specifier => specifier.type === 'ImportSpecifier',
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (hasNamedSpecifiers) {
|
|
90
|
+
const namedSpecifiers = flashListImport.specifiers.filter(
|
|
91
|
+
specifier => specifier.type === 'ImportSpecifier',
|
|
92
|
+
);
|
|
93
|
+
const lastNamedSpecifier = namedSpecifiers[namedSpecifiers.length - 1];
|
|
94
|
+
fixes.push(fixer.insertTextAfter(lastNamedSpecifier, ', FlashList'));
|
|
95
|
+
} else if (flashListImport.specifiers.length > 0) {
|
|
96
|
+
const lastSpecifier = flashListImport.specifiers[flashListImport.specifiers.length - 1];
|
|
97
|
+
fixes.push(fixer.insertTextAfter(lastSpecifier, ', { FlashList }'));
|
|
98
|
+
} else {
|
|
99
|
+
fixes.push(
|
|
100
|
+
fixer.replaceText(flashListImport, "import { FlashList } from '@shopify/flash-list';"),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
fixes.push(fixer.insertTextAfter(node, "\nimport { FlashList } from '@shopify/flash-list';"));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return fixes;
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
1
118
|
/** @type {import('eslint').Linter.Config} */
|
|
2
119
|
const config = {
|
|
3
120
|
files: ['**/*.{ts,tsx}'],
|
|
121
|
+
plugins: {
|
|
122
|
+
flashList: flashListPlugin,
|
|
123
|
+
},
|
|
4
124
|
rules: {
|
|
5
125
|
'no-redeclare': 'off',
|
|
6
126
|
'@typescript-eslint/no-redeclare': ['error', { ignoreDeclarationMerge: true }],
|
|
127
|
+
'flashList/prefer-flash-list': 'error',
|
|
7
128
|
'no-restricted-properties': [
|
|
8
129
|
'error',
|
|
9
130
|
{
|