@hero-design/eslint-plugin 9.2.0-rc.1 → 9.2.1-alpha.0
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/.turbo/turbo-lint.log +0 -1
- package/.turbo/turbo-test.log +13 -1
- package/CHANGELOG.md +37 -0
- package/eslint.config.js +31 -0
- package/lib/index.js +15 -298
- package/lib/rules/banning-snowflake-approve-comment.js +32 -0
- package/lib/rules/no-deprecated-component-prop-next.js +4 -0
- package/lib/rules/no-deprecated-theme-key.js +3 -15
- package/lib/rules/no-direct-color-palette-access.js +56 -0
- package/lib/rules/react-no-text-outside-typography.js +216 -0
- package/lib/utils.js +17 -0
- package/package.json +9 -6
- package/tests/lib/rules/banning-snowflake-approve-comment.js +46 -0
- package/tests/lib/rules/no-direct-color-palette-access.js +45 -0
- package/tests/lib/rules/react-no-text-outside-typography.js +248 -0
- package/.eslintrc.js +0 -19
- package/.turbo/turbo-publish:npm.log +0 -0
package/.turbo/turbo-lint.log
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
$ eslint .
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
PASS tests/lib/rules/react-no-text-outside-typography.js
|
|
2
|
+
PASS tests/lib/rules/no-deprecated-component-prop-value.js
|
|
3
|
+
PASS tests/lib/rules/no-deprecated-component-prop.js
|
|
4
|
+
PASS tests/lib/rules/no-deprecated-theme-key.js
|
|
5
|
+
PASS tests/lib/rules/not-recommended-import.js
|
|
6
|
+
PASS tests/lib/rules/banning-snowflake-approve-comment.js
|
|
7
|
+
PASS tests/lib/rules/no-direct-color-palette-access.js
|
|
8
|
+
|
|
9
|
+
Test Suites: 7 passed, 7 total
|
|
10
|
+
Tests: 90 passed, 90 total
|
|
11
|
+
Snapshots: 0 total
|
|
12
|
+
Time: 12.224 s
|
|
13
|
+
Ran all test suites.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# @hero-design/eslint-plugin
|
|
2
|
+
|
|
3
|
+
## 9.2.1-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- test release workflow
|
|
8
|
+
|
|
9
|
+
## 9.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#3327](https://github.com/Thinkei/hero-design/pull/3327) [`a405687ba571a1dffd92cb23d3d6ae6159fdf904`](https://github.com/Thinkei/hero-design/commit/a405687ba571a1dffd92cb23d3d6ae6159fdf904) Thanks [@luanlai2201](https://github.com/luanlai2201)! - Add banning-snowflake-approve-comment rule
|
|
14
|
+
|
|
15
|
+
## 9.1.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- [#3197](https://github.com/Thinkei/hero-design/pull/3197) [`36c71a4a7`](https://github.com/Thinkei/hero-design/commit/36c71a4a7719bd5f09925a9d88e197135696d0c9) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - Add react-no-text-outside-typography rule for react
|
|
20
|
+
|
|
21
|
+
## 9.0.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- [#3187](https://github.com/Thinkei/hero-design/pull/3187) [`c580bccd6`](https://github.com/Thinkei/hero-design/commit/c580bccd6958dd5accc6f7c17192a822630e6536) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - Implement no-direct-color-palette-access rule
|
|
26
|
+
|
|
27
|
+
## 9.0.0
|
|
28
|
+
|
|
29
|
+
### Major Changes
|
|
30
|
+
|
|
31
|
+
- [#2563](https://github.com/Thinkei/hero-design/pull/2563) [`0254e47a8`](https://github.com/Thinkei/hero-design/commit/0254e47a838f0f431c3d72306b945247786ea7d1) Thanks [@luanlai2201](https://github.com/luanlai2201)! - [Internal] Remove eslint no-invalid-access-theme rule
|
|
32
|
+
|
|
33
|
+
## 8.42.5
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- [#2302](https://github.com/Thinkei/hero-design/pull/2302) [`2293190d1`](https://github.com/Thinkei/hero-design/commit/2293190d105fb97dc699e39990c3148f3509fafb) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - Upgrade expo sdk and react-native version
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const { FlatCompat } = require('@eslint/eslintrc');
|
|
2
|
+
const js = require('@eslint/js');
|
|
3
|
+
|
|
4
|
+
const compat = new FlatCompat({
|
|
5
|
+
baseDirectory: __dirname,
|
|
6
|
+
recommendedConfig: js.configs.recommended,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
module.exports = [
|
|
10
|
+
...compat.extends(
|
|
11
|
+
'eslint:recommended',
|
|
12
|
+
'plugin:eslint-plugin/recommended',
|
|
13
|
+
'plugin:node/recommended'
|
|
14
|
+
),
|
|
15
|
+
{
|
|
16
|
+
files: ['**/*.js', '**/*.ts'],
|
|
17
|
+
languageOptions: {
|
|
18
|
+
globals: {
|
|
19
|
+
node: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
files: ['tests/**/*.js'],
|
|
25
|
+
languageOptions: {
|
|
26
|
+
globals: {
|
|
27
|
+
jest: true,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
];
|
package/lib/index.js
CHANGED
|
@@ -14,213 +14,6 @@ const requireIndex = require('requireindex');
|
|
|
14
14
|
// Plugin Definition
|
|
15
15
|
//------------------------------------------------------------------------------
|
|
16
16
|
|
|
17
|
-
const themeKeysMap = [
|
|
18
|
-
{
|
|
19
|
-
old: 'colors.globalPrimary',
|
|
20
|
-
new: 'colors.onDefaultGlobalSurface',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
old: 'colors.globalPrimaryLight',
|
|
24
|
-
new: 'colors.globalPrimaryLight',
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
old: 'colors.globalPrimaryBackground',
|
|
28
|
-
new: 'colors.defaultGlobalSurface',
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
old: 'colors.primaryLight',
|
|
32
|
-
new: 'colors.secondary',
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
old: 'colors.primaryDark',
|
|
36
|
-
new: 'colors.primary',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
old: 'colors.primaryBackground',
|
|
40
|
-
new: 'colors.highlightedSurface',
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
old: 'colors.primaryBackgroundDark',
|
|
44
|
-
new: 'colors.mutedOnDefaultGlobalSurface',
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
old: 'colors.secondaryLight',
|
|
48
|
-
new: 'colors.secondaryLight',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
old: 'colors.secondaryBackground',
|
|
52
|
-
new: 'colors.secondaryBackground',
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
old: 'colors.infoMediumLight',
|
|
56
|
-
new: 'colors.mutedInfo',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
old: 'colors.infoLight',
|
|
60
|
-
new: 'colors.mutedInfo',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
old: 'colors.infoBackground',
|
|
64
|
-
new: 'colors.infoSurface',
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
old: 'colors.successLight',
|
|
68
|
-
new: 'colors.mutedSuccess',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
old: 'colors.successDark',
|
|
72
|
-
new: 'colors.success',
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
old: 'colors.successBackground',
|
|
76
|
-
new: 'colors.successSurface',
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
old: 'colors.danger',
|
|
80
|
-
new: 'colors.error',
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
old: 'colors.dangerMediumLight',
|
|
84
|
-
new: 'colors.mutedError',
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
old: 'colors.dangerLight',
|
|
88
|
-
new: 'colors.mutedError',
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
old: 'colors.dangerBackground',
|
|
92
|
-
new: 'colors.errorSurface',
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
old: 'colors.warningLight',
|
|
96
|
-
new: 'colors.mutedWarning',
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
old: 'colors.warningDark',
|
|
100
|
-
new: 'colors.warning',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
old: 'colors.warningBackground',
|
|
104
|
-
new: 'colors.warningSurface',
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
old: 'colors.platformBackground',
|
|
108
|
-
new: 'colors.defaultGlobalSurface',
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
old: 'colors.backgroundLight',
|
|
112
|
-
new: 'colors.neutralGlobalSurface',
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
old: 'colors.backgroundDark',
|
|
116
|
-
new: 'colors.darkGlobalSurface',
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
old: 'colors.text',
|
|
120
|
-
new: 'colors.onDefaultGlobalSurface',
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
old: 'colors.subduedText',
|
|
124
|
-
new: 'colors.mutedOnDefaultGlobalSurface',
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
old: 'colors.disabledText',
|
|
128
|
-
new: 'colors.inactiveOnDefaultGlobalSurface',
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
old: 'colors.disabledLightText',
|
|
132
|
-
new: 'colors.disabledOnDefaultGlobalSurface',
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
old: 'colors.invertedText',
|
|
136
|
-
new: 'colors.onDarkGlobalSurface',
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
old: 'colors.outline',
|
|
140
|
-
new: 'colors.secondaryOutline',
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
old: 'colors.archivedLight',
|
|
144
|
-
new: 'colors.disabledOnDefaultGlobalSurface',
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
old: 'colors.archivedDark',
|
|
148
|
-
new: 'colors.archived',
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
old: 'colors.archivedBackground',
|
|
152
|
-
new: 'colors.archivedSurface',
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
old: 'colors.black',
|
|
156
|
-
new: 'colors.onDefaultGlobalSurface',
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
old: 'colors.inactiveBackground',
|
|
160
|
-
new: 'colors.inactiveOnDefaultGlobalSurface',
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
old: 'colors.shadow',
|
|
164
|
-
new: 'colors.secondaryOutline',
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
old: 'colors.mutedGlobalPrimary',
|
|
168
|
-
new: 'colors.mutedOnDefaultGlobalSurface',
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
old: 'colors.onGlobalPrimary',
|
|
172
|
-
new: 'colors.onDefaultGlobalSurface',
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
old: 'colors.globalSecondary',
|
|
176
|
-
new: 'colors.secondary',
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
old: 'colors.globalPrimaryOutline',
|
|
180
|
-
new: 'colors.primaryOutline',
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
old: 'colors.globalSecondaryOutline',
|
|
184
|
-
new: 'colors.secondaryOutline',
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
old: 'colors.mutedPrimary',
|
|
188
|
-
new: 'colors.mutedPrimary',
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
old: 'colors.highlightedSecondarySurface',
|
|
192
|
-
new: 'colors.highlightedSecondarySurface',
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
old: 'colors.mutedSecondary',
|
|
196
|
-
new: 'colors.mutedSecondary',
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
old: 'colors.disabledSecondary',
|
|
200
|
-
new: 'colors.disabledSecondary',
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
old: 'colors.lightHighlightedSurface',
|
|
204
|
-
new: 'colors.highlightedSurface',
|
|
205
|
-
},
|
|
206
|
-
];
|
|
207
|
-
const deprecatedThemeColors = themeKeysMap.map((c) => c.old.split('.')[1]);
|
|
208
|
-
const boxColorProps = [
|
|
209
|
-
'backgroundColor',
|
|
210
|
-
'bgColor',
|
|
211
|
-
'borderColor',
|
|
212
|
-
'borderTopColor',
|
|
213
|
-
'borderBottomColor',
|
|
214
|
-
'borderStartColor',
|
|
215
|
-
'borderEndColor',
|
|
216
|
-
'borderLeftColor',
|
|
217
|
-
'borderRightColor',
|
|
218
|
-
];
|
|
219
|
-
const deprecatedBoxPropValues = boxColorProps.map((prop) => ({
|
|
220
|
-
name: prop,
|
|
221
|
-
values: deprecatedThemeColors,
|
|
222
|
-
}));
|
|
223
|
-
|
|
224
17
|
// import all rules in lib/rules
|
|
225
18
|
module.exports = {
|
|
226
19
|
rules: requireIndex(__dirname + '/rules'),
|
|
@@ -228,101 +21,18 @@ module.exports = {
|
|
|
228
21
|
internalRn: {
|
|
229
22
|
plugins: ['@hero-design'],
|
|
230
23
|
rules: {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
keys: themeKeysMap,
|
|
235
|
-
},
|
|
236
|
-
],
|
|
237
|
-
'@hero-design/no-deprecated-component-prop': [
|
|
238
|
-
'error',
|
|
239
|
-
{
|
|
240
|
-
package: '@hero-design/rn',
|
|
241
|
-
components: [
|
|
242
|
-
{ name: 'Card', props: ['variant'] },
|
|
243
|
-
{ name: 'Switch', props: ['size'] },
|
|
244
|
-
{
|
|
245
|
-
name: 'Select',
|
|
246
|
-
props: ['onDimiss', 'numberOfLines', 'inputProps.required'],
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
name: 'Select.Multi',
|
|
250
|
-
props: ['onDimiss', 'numberOfLines', 'inputProps.required'],
|
|
251
|
-
},
|
|
252
|
-
{ name: 'Toast.Provider', props: ['position'] },
|
|
253
|
-
],
|
|
254
|
-
},
|
|
255
|
-
],
|
|
256
|
-
'@hero-design/no-deprecated-component-prop-value': [
|
|
257
|
-
'error',
|
|
24
|
+
// Rules for the next major version
|
|
25
|
+
'@hero-design/no-deprecated-component-prop-next': [
|
|
26
|
+
'warn',
|
|
258
27
|
{
|
|
259
28
|
package: '@hero-design/rn',
|
|
260
29
|
components: [
|
|
30
|
+
{ name: 'Tag', props: ['variant'] },
|
|
31
|
+
{ name: 'FAB.ActionGroup', props: ['headerTitle'] },
|
|
32
|
+
{ name: 'Checkbox', props: ['withBorder'] },
|
|
261
33
|
{
|
|
262
|
-
name: '
|
|
263
|
-
props: [
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
name: 'Button',
|
|
267
|
-
props: [{ name: 'variant', values: ['basic-transparent'] }],
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
name: 'Button.Icon',
|
|
271
|
-
props: [
|
|
272
|
-
{
|
|
273
|
-
name: 'icon',
|
|
274
|
-
values: [
|
|
275
|
-
'carat-down-small',
|
|
276
|
-
'carat-down',
|
|
277
|
-
'carat-left-small',
|
|
278
|
-
'carat-left',
|
|
279
|
-
'carat-right-small',
|
|
280
|
-
'carat-right',
|
|
281
|
-
'carat-up-small',
|
|
282
|
-
'carat-up',
|
|
283
|
-
],
|
|
284
|
-
},
|
|
285
|
-
],
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
name: 'Button.Utility',
|
|
289
|
-
props: [
|
|
290
|
-
{
|
|
291
|
-
name: 'icon',
|
|
292
|
-
values: [
|
|
293
|
-
'carat-down-small',
|
|
294
|
-
'carat-down',
|
|
295
|
-
'carat-left-small',
|
|
296
|
-
'carat-left',
|
|
297
|
-
'carat-right-small',
|
|
298
|
-
'carat-right',
|
|
299
|
-
'carat-up-small',
|
|
300
|
-
'carat-up',
|
|
301
|
-
],
|
|
302
|
-
},
|
|
303
|
-
],
|
|
304
|
-
},
|
|
305
|
-
{
|
|
306
|
-
name: 'Icon',
|
|
307
|
-
props: [
|
|
308
|
-
{
|
|
309
|
-
name: 'icon',
|
|
310
|
-
values: [
|
|
311
|
-
'carat-down-small',
|
|
312
|
-
'carat-down',
|
|
313
|
-
'carat-left-small',
|
|
314
|
-
'carat-left',
|
|
315
|
-
'carat-right-small',
|
|
316
|
-
'carat-right',
|
|
317
|
-
'carat-up-small',
|
|
318
|
-
'carat-up',
|
|
319
|
-
],
|
|
320
|
-
},
|
|
321
|
-
],
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
name: 'Box',
|
|
325
|
-
props: deprecatedBoxPropValues,
|
|
34
|
+
name: 'SectionHeading',
|
|
35
|
+
props: ['fontSize', 'fontWeight'],
|
|
326
36
|
},
|
|
327
37
|
],
|
|
328
38
|
},
|
|
@@ -408,5 +118,12 @@ module.exports = {
|
|
|
408
118
|
],
|
|
409
119
|
},
|
|
410
120
|
},
|
|
121
|
+
recommendedReact: {
|
|
122
|
+
plugins: ['@hero-design'],
|
|
123
|
+
rules: {
|
|
124
|
+
'@hero-design/no-direct-color-palette-access': 'error',
|
|
125
|
+
'@hero-design/react-no-text-outside-typography': 'warn',
|
|
126
|
+
}
|
|
127
|
+
}
|
|
411
128
|
},
|
|
412
129
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
meta: {
|
|
3
|
+
type: 'problem',
|
|
4
|
+
docs: {
|
|
5
|
+
description:
|
|
6
|
+
'Disallow the use of comments that include @snowflake-guard/',
|
|
7
|
+
},
|
|
8
|
+
messages: {
|
|
9
|
+
noSnowflakeGuard:
|
|
10
|
+
'Comments including @snowflake-guard/ are not allowed. Please contact Andromeda team for the approval.',
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
},
|
|
14
|
+
create(context) {
|
|
15
|
+
return {
|
|
16
|
+
Program() {
|
|
17
|
+
const sourceCode = context.getSourceCode();
|
|
18
|
+
const comments = sourceCode.getAllComments();
|
|
19
|
+
|
|
20
|
+
comments.forEach((comment) => {
|
|
21
|
+
// Check if the comment includes @snowflake-guard/
|
|
22
|
+
if (comment.value.includes('@snowflake-guard/')) {
|
|
23
|
+
context.report({
|
|
24
|
+
node: comment,
|
|
25
|
+
messageId: 'noSnowflakeGuard',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
};
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
+
const { findIndentifierPath } = require('../utils');
|
|
8
|
+
|
|
7
9
|
//------------------------------------------------------------------------------
|
|
8
10
|
// Rule Definition
|
|
9
11
|
//------------------------------------------------------------------------------
|
|
@@ -46,27 +48,13 @@ module.exports = {
|
|
|
46
48
|
const oldKeys = context.options[0].keys.map((k) => k.old);
|
|
47
49
|
const newKeys = context.options[0].keys.map((k) => k.new);
|
|
48
50
|
|
|
49
|
-
const findPath = (node, identifiers) => {
|
|
50
|
-
const property = node.property;
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
property != null &&
|
|
54
|
-
property.type === 'Identifier' &&
|
|
55
|
-
property.name != null
|
|
56
|
-
) {
|
|
57
|
-
return findPath(node.parent, [...identifiers, property.name]);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return identifiers.join('.');
|
|
61
|
-
};
|
|
62
|
-
|
|
63
51
|
return {
|
|
64
52
|
MemberExpression(node) {
|
|
65
53
|
const object = node.object;
|
|
66
54
|
if (object == null) return;
|
|
67
55
|
|
|
68
56
|
if (object.type === 'Identifier' && object.name === 'theme') {
|
|
69
|
-
const path =
|
|
57
|
+
const path = findIndentifierPath(node, []);
|
|
70
58
|
const deprecatedKeyIndex = oldKeys.findIndex((k) => k === path);
|
|
71
59
|
|
|
72
60
|
if (deprecatedKeyIndex >= 0) {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Disallow direct access of color palette.
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const { findIndentifierPath } = require('../utils');
|
|
7
|
+
|
|
8
|
+
//------------------------------------------------------------------------------
|
|
9
|
+
// Rule Definition
|
|
10
|
+
//------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
13
|
+
module.exports = {
|
|
14
|
+
meta: {
|
|
15
|
+
type: 'problem',
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'Disallow direct access of color palette.',
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
invalidColorAccess: 'Unexpected direct access of palette colors, use semantic colors instead.',
|
|
21
|
+
},
|
|
22
|
+
schema: [],
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
create(context) {
|
|
26
|
+
return {
|
|
27
|
+
MemberExpression(node) {
|
|
28
|
+
const object = node.object;
|
|
29
|
+
if (object == null) return;
|
|
30
|
+
|
|
31
|
+
// For example: theme.colors.pallete.redLight30
|
|
32
|
+
if (object.type === 'Identifier' && object.name === 'theme') {
|
|
33
|
+
const path = findIndentifierPath(node, []);
|
|
34
|
+
|
|
35
|
+
if (path.includes('colors.palette')) {
|
|
36
|
+
context.report({
|
|
37
|
+
node,
|
|
38
|
+
messageId: 'invalidColorAccess',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// For example: colors.pallete.redLight30
|
|
43
|
+
else if (object.type === 'Identifier' && object.name === 'colors') {
|
|
44
|
+
const path = findIndentifierPath(node, []);
|
|
45
|
+
|
|
46
|
+
if (path.includes('palette')) {
|
|
47
|
+
context.report({
|
|
48
|
+
node,
|
|
49
|
+
messageId: 'invalidColorAccess',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
const notRecommendedList = [
|
|
2
|
+
'div',
|
|
3
|
+
'p',
|
|
4
|
+
'span',
|
|
5
|
+
'h1',
|
|
6
|
+
'h2',
|
|
7
|
+
'h3',
|
|
8
|
+
'h4',
|
|
9
|
+
'h5',
|
|
10
|
+
'h6',
|
|
11
|
+
'a',
|
|
12
|
+
'strong',
|
|
13
|
+
'em',
|
|
14
|
+
'b',
|
|
15
|
+
'i',
|
|
16
|
+
'u',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// Get the parent tag name of the node
|
|
20
|
+
const getParentTagName = (node) => {
|
|
21
|
+
let parent = node.parent;
|
|
22
|
+
while (parent) {
|
|
23
|
+
if (parent.type === 'JSXElement') {
|
|
24
|
+
return parent.openingElement.name.name;
|
|
25
|
+
}
|
|
26
|
+
parent = parent.parent;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Find the Typography component in the parent hierarchy
|
|
32
|
+
// and return the value of tagName prop and the level of nested component
|
|
33
|
+
const findTypography = (node, typographyNames) => {
|
|
34
|
+
let parent = node.parent;
|
|
35
|
+
let level = 0;
|
|
36
|
+
let tagName = null;
|
|
37
|
+
let found = false;
|
|
38
|
+
|
|
39
|
+
while (parent) {
|
|
40
|
+
if (
|
|
41
|
+
parent.type === 'JSXElement' &&
|
|
42
|
+
parent.openingElement.name.type === 'JSXMemberExpression' &&
|
|
43
|
+
typographyNames.includes(parent.openingElement.name.object.name)
|
|
44
|
+
) {
|
|
45
|
+
found = true;
|
|
46
|
+
const attributes = parent.openingElement.attributes;
|
|
47
|
+
for (let attr of attributes) {
|
|
48
|
+
if (attr.name && attr.name.name === 'tagName') {
|
|
49
|
+
tagName = attr.value.value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
parent = parent.parent;
|
|
55
|
+
level++;
|
|
56
|
+
}
|
|
57
|
+
return { tagName, level, found };
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Check if the direct parent element is in the notRecommendedList
|
|
61
|
+
const isParentNotRecommended = (node) => {
|
|
62
|
+
let parentElement = node.parent;
|
|
63
|
+
while (parentElement && parentElement.type !== 'JSXElement') {
|
|
64
|
+
parentElement = parentElement.parent;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
parentElement &&
|
|
69
|
+
parentElement.openingElement.name.type === 'JSXIdentifier' &&
|
|
70
|
+
notRecommendedList.includes(parentElement.openingElement.name.name)
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const checkNode = (node, context, typographyNames) => {
|
|
75
|
+
const {
|
|
76
|
+
tagName,
|
|
77
|
+
level,
|
|
78
|
+
found: foundTypography,
|
|
79
|
+
} = findTypography(node, typographyNames);
|
|
80
|
+
|
|
81
|
+
// Typography not found, check if the direct parent is in the notRecommendedList
|
|
82
|
+
if (!foundTypography && isParentNotRecommended(node)) {
|
|
83
|
+
context.report({
|
|
84
|
+
node,
|
|
85
|
+
messageId: 'textNodeOutsideTypography',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Typography found, handle edge cases as documented in
|
|
90
|
+
// https://design.employmenthero.com/web/Components/Typography/#typographytext
|
|
91
|
+
if (foundTypography) {
|
|
92
|
+
switch (tagName) {
|
|
93
|
+
case 'p':
|
|
94
|
+
case '':
|
|
95
|
+
case 'span':
|
|
96
|
+
case 'label': {
|
|
97
|
+
if (level > 1) {
|
|
98
|
+
// Not allowing nested of nested nodes
|
|
99
|
+
context.report({
|
|
100
|
+
node,
|
|
101
|
+
messageId: 'textNodeOutsideTypography',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case 'div': {
|
|
107
|
+
// Allowed cases:
|
|
108
|
+
// 2 level nested with unordered list
|
|
109
|
+
// 2 level nested elements with p
|
|
110
|
+
const parentTagName = getParentTagName(node);
|
|
111
|
+
const grandParentTagName = getParentTagName(node.parent);
|
|
112
|
+
|
|
113
|
+
const isAllowedUnorderedList =
|
|
114
|
+
level === 2 && parentTagName === 'li' && grandParentTagName === 'ul';
|
|
115
|
+
|
|
116
|
+
const isAllowedParagraph = level === 2 && grandParentTagName === 'p';
|
|
117
|
+
|
|
118
|
+
if (!isAllowedParagraph && !isAllowedUnorderedList && level > 1) {
|
|
119
|
+
context.report({
|
|
120
|
+
node,
|
|
121
|
+
messageId: 'textNodeOutsideTypography',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
function containsIntlFormatMessage(expression) {
|
|
131
|
+
if (expression === null || expression === undefined) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (
|
|
136
|
+
expression.type === 'CallExpression' &&
|
|
137
|
+
expression.callee.type === 'MemberExpression' &&
|
|
138
|
+
expression.callee.object.name === 'Intl' &&
|
|
139
|
+
expression.callee.property.name === 'formatMessage'
|
|
140
|
+
) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Example: {condition1 && Intl.formatMessage({ id: 'someId' })}
|
|
145
|
+
// Also works for multiple logical expressions
|
|
146
|
+
if (expression.type === 'LogicalExpression') {
|
|
147
|
+
return (
|
|
148
|
+
containsIntlFormatMessage(expression.left) ||
|
|
149
|
+
containsIntlFormatMessage(expression.right)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (expression.type === 'ConditionalExpression') {
|
|
154
|
+
return (
|
|
155
|
+
containsIntlFormatMessage(expression.consequent) ||
|
|
156
|
+
containsIntlFormatMessage(expression.alternate)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
module.exports = {
|
|
164
|
+
meta: {
|
|
165
|
+
type: 'problem',
|
|
166
|
+
docs: {
|
|
167
|
+
description: 'Recommend using text inside Typography component.',
|
|
168
|
+
recommended: false,
|
|
169
|
+
},
|
|
170
|
+
schema: [],
|
|
171
|
+
messages: {
|
|
172
|
+
textNodeOutsideTypography:
|
|
173
|
+
'Text nodes should be inside Typography component.',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
create(context) {
|
|
177
|
+
let typographyNames = ['Typography'];
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
ImportDeclaration(node) {
|
|
181
|
+
if (node.source.value === '@hero-design/react') {
|
|
182
|
+
node.specifiers.forEach((specifier) => {
|
|
183
|
+
if (
|
|
184
|
+
specifier.imported &&
|
|
185
|
+
specifier.imported.name === 'Typography'
|
|
186
|
+
) {
|
|
187
|
+
specifier.local.name !== 'Typography' &&
|
|
188
|
+
typographyNames.push(specifier.local.name);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
VariableDeclarator(node) {
|
|
194
|
+
// Handle local assignments
|
|
195
|
+
if (
|
|
196
|
+
node.init &&
|
|
197
|
+
node.init.type === 'Identifier' &&
|
|
198
|
+
typographyNames.includes(node.init.name)
|
|
199
|
+
) {
|
|
200
|
+
node.id.name !== 'Typography' && typographyNames.push(node.id.name);
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
JSXText(node) {
|
|
204
|
+
const trimmedValue = node.value.trim();
|
|
205
|
+
if (trimmedValue) {
|
|
206
|
+
checkNode(node, context, typographyNames);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
JSXExpressionContainer(node) {
|
|
210
|
+
if (containsIntlFormatMessage(node.expression)) {
|
|
211
|
+
checkNode(node, context, typographyNames);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
};
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const findIndentifierPath = (node, identifiers) => {
|
|
2
|
+
const property = node.property;
|
|
3
|
+
|
|
4
|
+
if (
|
|
5
|
+
property != null &&
|
|
6
|
+
property.type === 'Identifier' &&
|
|
7
|
+
property.name != null
|
|
8
|
+
) {
|
|
9
|
+
return findIndentifierPath(node.parent, [...identifiers, property.name]);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return identifiers.join('.');
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
findIndentifierPath,
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hero-design/eslint-plugin",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.1-alpha.0",
|
|
4
4
|
"description": "Hero Design's eslint plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"exports": "./lib/index.js",
|
|
13
13
|
"prettier": "prettier-config-hd",
|
|
14
14
|
"scripts": {
|
|
15
|
-
"lint": "eslint
|
|
15
|
+
"lint": "eslint lib tests",
|
|
16
16
|
"test": "jest --runInBand",
|
|
17
17
|
"test:watch": "jest --runInBand --watch",
|
|
18
18
|
"test:ci": "jest --runInBand --logHeapUsage",
|
|
@@ -22,14 +22,17 @@
|
|
|
22
22
|
"requireindex": "^1.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"eslint": "^
|
|
25
|
+
"@eslint/compat": "^1.1.1",
|
|
26
|
+
"@eslint/eslintrc": "^3.1.0",
|
|
27
|
+
"@eslint/js": "^9.8.0",
|
|
28
|
+
"eslint": "^8.56.0",
|
|
26
29
|
"eslint-plugin-eslint-plugin": "^5.0.0",
|
|
27
30
|
"eslint-plugin-node": "^11.1.0",
|
|
28
|
-
"jest": "^
|
|
29
|
-
"prettier-config-hd": "
|
|
31
|
+
"jest": "^29.2.1",
|
|
32
|
+
"prettier-config-hd": "8.42.5-alpha.0"
|
|
30
33
|
},
|
|
31
34
|
"engines": {
|
|
32
|
-
"node": "^14.17.0 || ^16.0.0 ||
|
|
35
|
+
"node": "^14.17.0 || ^16.0.0 || ^18.0.0 || >=20.0.0"
|
|
33
36
|
},
|
|
34
37
|
"peerDependencies": {
|
|
35
38
|
"eslint": ">=7"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const { RuleTester } = require('eslint');
|
|
2
|
+
const rule = require('../../../lib/rules/banning-snowflake-approve-comment');
|
|
3
|
+
|
|
4
|
+
const ruleTester = new RuleTester();
|
|
5
|
+
|
|
6
|
+
// Define valid and invalid test cases
|
|
7
|
+
ruleTester.run('no-snowflake-guard', rule, {
|
|
8
|
+
// Valid cases (should not trigger the rule)
|
|
9
|
+
valid: [
|
|
10
|
+
'// A normal comment without snowflake-guard',
|
|
11
|
+
'// Another valid comment',
|
|
12
|
+
'/* @no-snowflake-guard */',
|
|
13
|
+
'console.log("no issues here");',
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
// Invalid cases (should trigger the rule)
|
|
17
|
+
invalid: [
|
|
18
|
+
{
|
|
19
|
+
code: '// @snowflake-guard/none-css-classname', // Triggers the rule
|
|
20
|
+
errors: [
|
|
21
|
+
{
|
|
22
|
+
message:
|
|
23
|
+
'Comments including @snowflake-guard/ are not allowed. Please contact Andromeda team for the approval.',
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
code: '// @snowflake-guard/another-pattern', // Triggers the rule
|
|
29
|
+
errors: [
|
|
30
|
+
{
|
|
31
|
+
message:
|
|
32
|
+
'Comments including @snowflake-guard/ are not allowed. Please contact Andromeda team for the approval.',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
code: '/* @snowflake-guard/custom-pattern */', // Triggers the rule for block comments
|
|
38
|
+
errors: [
|
|
39
|
+
{
|
|
40
|
+
message:
|
|
41
|
+
'Comments including @snowflake-guard/ are not allowed. Please contact Andromeda team for the approval.',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const rule = require('../../../lib/rules/no-direct-color-palette-access');
|
|
2
|
+
const RuleTester = require('eslint').RuleTester;
|
|
3
|
+
|
|
4
|
+
//------------------------------------------------------------------------------
|
|
5
|
+
// Tests
|
|
6
|
+
//------------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
const config = {
|
|
9
|
+
parserOptions: {
|
|
10
|
+
sourceType: 'module',
|
|
11
|
+
ecmaVersion: 6,
|
|
12
|
+
ecmaFeatures: { jsx: true },
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const ruleTester = new RuleTester();
|
|
17
|
+
ruleTester.run('no-direct-color-palette-access', rule, {
|
|
18
|
+
valid: [
|
|
19
|
+
{
|
|
20
|
+
code: 'const color = theme.colors.hoverDanger',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
code: '<Box sx={{ backgroundColor: theme.colors.hoverDanger }} />',
|
|
24
|
+
},
|
|
25
|
+
].map((test) => ({ ...test, ...config })),
|
|
26
|
+
invalid: [
|
|
27
|
+
{
|
|
28
|
+
code: 'const color = theme.colors.palette.redLight30',
|
|
29
|
+
errors: [{ messageId: 'invalidColorAccess' }],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
code: 'const color = theme.colors.palette',
|
|
33
|
+
errors: [{ messageId: 'invalidColorAccess' }],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
code: '<Box sx={{ backgroundColor: theme.colors.palette.redLight30 }} />',
|
|
37
|
+
errors: [{ messageId: 'invalidColorAccess' }],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
code: `const colors = theme.colors;
|
|
41
|
+
const color = colors.palette.redLight30`,
|
|
42
|
+
errors: [{ messageId: 'invalidColorAccess' }],
|
|
43
|
+
}
|
|
44
|
+
].map((test) => ({ ...test, ...config })),
|
|
45
|
+
});
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
const rule = require('../../../lib/rules/react-no-text-outside-typography');
|
|
2
|
+
const RuleTester = require('eslint').RuleTester;
|
|
3
|
+
|
|
4
|
+
//------------------------------------------------------------------------------
|
|
5
|
+
// Tests
|
|
6
|
+
//------------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
const config = {
|
|
9
|
+
parserOptions: {
|
|
10
|
+
sourceType: 'module',
|
|
11
|
+
ecmaVersion: 6,
|
|
12
|
+
ecmaFeatures: { jsx: true },
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const ruleTester = new RuleTester();
|
|
17
|
+
ruleTester.run('react-no-text-outside-typography', rule, {
|
|
18
|
+
valid: [
|
|
19
|
+
// Common cases
|
|
20
|
+
{
|
|
21
|
+
code: '<Typography.Text>Content</Typography.Text>',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
code: '<Typography.Title>Content</Typography.Title>',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
code: `<Typography.Text>
|
|
28
|
+
Click <a href='..'>here</a>
|
|
29
|
+
</Typography.Text>`,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
code: `<Typography.Text>
|
|
33
|
+
<Box>Content</Box>
|
|
34
|
+
</Typography.Text>
|
|
35
|
+
`,
|
|
36
|
+
},
|
|
37
|
+
// With Intl.formatMessage and conditions
|
|
38
|
+
{
|
|
39
|
+
code: `<Typography.Text>
|
|
40
|
+
<Box>{Intl.formatMessage({ id: 'someId' })}</Box>
|
|
41
|
+
</Typography.Text>
|
|
42
|
+
`,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
code: `<Typography.Text>
|
|
46
|
+
<Box>{condition1 && Intl.formatMessage({ id: 'someId' })}</Box>
|
|
47
|
+
</Typography.Text>
|
|
48
|
+
`,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
code: `<Typography.Text>
|
|
52
|
+
<Box>{condition1 ? Intl.formatMessage({ id: 'someId' }) : null}</Box>
|
|
53
|
+
</Typography.Text>
|
|
54
|
+
`,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
code: `
|
|
58
|
+
<Typography.Text>
|
|
59
|
+
{Intl.formatMessage({ id: 'someId' })}
|
|
60
|
+
</Typography.Text>`,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
code: `
|
|
64
|
+
<Typography.Text>
|
|
65
|
+
{condition1 && Intl.formatMessage({ id: 'someId' })}
|
|
66
|
+
</Typography.Text>`,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
code: `
|
|
70
|
+
<Typography.Text>
|
|
71
|
+
{condition1 ? Intl.formatMessage({ id: 'someId' }) : null}
|
|
72
|
+
</Typography.Text>`,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
code: `
|
|
76
|
+
<Typography.Text>
|
|
77
|
+
{condition1 ? Intl.formatMessage({ id: 'someId' }) : Intl.formatMessage({ id: 'someId2' })}
|
|
78
|
+
</Typography.Text>`,
|
|
79
|
+
},
|
|
80
|
+
// Custom namings
|
|
81
|
+
{
|
|
82
|
+
code: `
|
|
83
|
+
import { Typography as HDTypography } from '@hero-design/react';
|
|
84
|
+
<HDTypography.Text>Content</HDTypography.Text>
|
|
85
|
+
`,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
code: `
|
|
89
|
+
import { Typography as HDTypography } from '@hero-design/react';
|
|
90
|
+
const { Text } = HDTypography;
|
|
91
|
+
<Text>Content</Text>
|
|
92
|
+
`,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
code: `
|
|
96
|
+
import { Typography } from '@hero-design/react';
|
|
97
|
+
const { Title } = Typography;
|
|
98
|
+
<Title>Content</Title>
|
|
99
|
+
`,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
code: `
|
|
103
|
+
import { Typography } from '@hero-design/react';
|
|
104
|
+
const { Title: HDTypographyTitle } = Typography;
|
|
105
|
+
<HDTypographyTitle>Content</HDTypographyTitle>
|
|
106
|
+
`,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
code: `
|
|
110
|
+
import { Typography } from '@hero-design/react';
|
|
111
|
+
const Title = Typography.Title;
|
|
112
|
+
<Title>Content</Title>
|
|
113
|
+
`,
|
|
114
|
+
},
|
|
115
|
+
// Exceptions with tagName prop
|
|
116
|
+
{
|
|
117
|
+
code: `
|
|
118
|
+
<Typography.Text tagName='p'>
|
|
119
|
+
<span>Content</span>
|
|
120
|
+
</Typography.Text>
|
|
121
|
+
`,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
code: `
|
|
125
|
+
<Typography.Text tagName='div'>
|
|
126
|
+
<ul>
|
|
127
|
+
<li>Content</li>
|
|
128
|
+
</ul>
|
|
129
|
+
</Typography.Text>
|
|
130
|
+
`,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
code: `
|
|
134
|
+
<Typography.Text tagName='div'>
|
|
135
|
+
<p>
|
|
136
|
+
<a>Content</a>
|
|
137
|
+
</p>
|
|
138
|
+
</Typography.Text>
|
|
139
|
+
`,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
code: `
|
|
143
|
+
<Typography.Text tagName='span'>
|
|
144
|
+
<span>Content</span>
|
|
145
|
+
</Typography.Text>
|
|
146
|
+
`,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
code: `
|
|
150
|
+
<Typography.Text tagName='label'>
|
|
151
|
+
<span>Content</span>
|
|
152
|
+
</Typography.Text>
|
|
153
|
+
`,
|
|
154
|
+
},
|
|
155
|
+
].map((test) => ({ ...test, ...config })),
|
|
156
|
+
invalid: [
|
|
157
|
+
// Common cases
|
|
158
|
+
{
|
|
159
|
+
code: '<div>Content</div>',
|
|
160
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
code: '<p>Content</p>',
|
|
164
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
code: '<h1>Content</h1>',
|
|
168
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
169
|
+
},
|
|
170
|
+
// With Intl.formatMessage and conditions
|
|
171
|
+
{
|
|
172
|
+
code: `
|
|
173
|
+
<div>
|
|
174
|
+
{Intl.formatMessage({ id: 'someId' })}
|
|
175
|
+
</div>`,
|
|
176
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
code: `
|
|
180
|
+
<div>
|
|
181
|
+
{ condition && Intl.formatMessage({ id: 'someId' })}
|
|
182
|
+
</div>`,
|
|
183
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
code: `
|
|
187
|
+
<div>
|
|
188
|
+
{ condition && condition2 && Intl.formatMessage({ id: 'someId' })}
|
|
189
|
+
</div>`,
|
|
190
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
code: `
|
|
194
|
+
<div>
|
|
195
|
+
{ condition && condition2 || condition3 && Intl.formatMessage({ id: 'someId' })}
|
|
196
|
+
</div>`,
|
|
197
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
code: `
|
|
201
|
+
<div>
|
|
202
|
+
{condition1 ? Intl.formatMessage({ id: 'someId' }) : null}
|
|
203
|
+
</div>`,
|
|
204
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
205
|
+
},
|
|
206
|
+
// Exceptions with tagName prop
|
|
207
|
+
{
|
|
208
|
+
code: `
|
|
209
|
+
<Typography.Text tagName='p'>
|
|
210
|
+
<span>
|
|
211
|
+
<span>Content</span>
|
|
212
|
+
</span>
|
|
213
|
+
</Typography.Text>
|
|
214
|
+
`,
|
|
215
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
code: `
|
|
219
|
+
<Typography.Text tagName='div'>
|
|
220
|
+
<span>
|
|
221
|
+
<li>Content</li>
|
|
222
|
+
</span>
|
|
223
|
+
</Typography.Text>
|
|
224
|
+
`,
|
|
225
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
code: `
|
|
229
|
+
<Typography.Text tagName='span'>
|
|
230
|
+
<span>
|
|
231
|
+
<span>Content</span>
|
|
232
|
+
</span>
|
|
233
|
+
</Typography.Text>
|
|
234
|
+
`,
|
|
235
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
code: `
|
|
239
|
+
<Typography.Text tagName='label'>
|
|
240
|
+
<span>
|
|
241
|
+
<span>Content</span>
|
|
242
|
+
</span>
|
|
243
|
+
</Typography.Text>
|
|
244
|
+
`,
|
|
245
|
+
errors: [{ messageId: 'textNodeOutsideTypography' }],
|
|
246
|
+
},
|
|
247
|
+
].map((test) => ({ ...test, ...config })),
|
|
248
|
+
});
|
package/.eslintrc.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
4
|
-
root: true,
|
|
5
|
-
extends: [
|
|
6
|
-
'eslint:recommended',
|
|
7
|
-
'plugin:eslint-plugin/recommended',
|
|
8
|
-
'plugin:node/recommended',
|
|
9
|
-
],
|
|
10
|
-
env: {
|
|
11
|
-
node: true,
|
|
12
|
-
},
|
|
13
|
-
overrides: [
|
|
14
|
-
{
|
|
15
|
-
files: ['tests/**/*.js'],
|
|
16
|
-
env: { jest: true },
|
|
17
|
-
},
|
|
18
|
-
],
|
|
19
|
-
};
|
|
File without changes
|