@tuomashatakka/eslint-config 2.6.2 → 3.1.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/.github/workflows/ci.yml +23 -0
- package/.github/workflows/publish.yml +45 -0
- package/AGENTS.md +29 -0
- package/bun.lock +60 -102
- package/eslint.config.mjs +1 -0
- package/index.mjs +7 -21
- package/package.json +11 -19
- package/plugins/no-inline-types/index.mjs +11 -0
- package/plugins/no-inline-types/rules/no-inline-multiline-types.mjs +181 -0
- package/plugins/omit/index.mjs +8 -0
- package/plugins/omit/rules/omit-unnecessary-parens-brackets.mjs +329 -0
- package/plugins/omit/utils.mjs +91 -0
- package/plugins/react-strict/index.mjs +19 -0
- package/plugins/react-strict/rules/jsx-prop-layout.mjs +100 -0
- package/plugins/react-strict/rules/no-complex-jsx-map.mjs +66 -0
- package/plugins/react-strict/rules/no-jsx-value-calculations.mjs +99 -0
- package/plugins/react-strict/rules/no-nested-divs.mjs +59 -0
- package/plugins/react-strict/rules/no-style-prop.mjs +43 -0
- package/plugins/react-strict/rules/prefer-no-use-effect.mjs +26 -0
- package/plugins/whitespaced/index.mjs +15 -0
- package/plugins/whitespaced/rules/aligned-assignments.mjs +385 -0
- package/plugins/whitespaced/rules/block-padding.mjs +289 -0
- package/plugins/whitespaced/rules/class-property-grouping.mjs +370 -0
- package/plugins/whitespaced/rules/consistent-line-spacing.mjs +266 -0
- package/plugins/whitespaced/rules/multiline-format.mjs +533 -0
- package/rules.mjs +101 -95
- package/test/fixtures/basic-javascript.js +5 -4
- package/test/fixtures/complex-patterns.ts +9 -7
- package/test/fixtures/edge-cases.js +12 -7
- package/test/fixtures/jsx-formatting.jsx +5 -4
- package/test/fixtures/omit-parens.invalid.ts +12 -0
- package/test/fixtures/omit-parens.valid.ts +13 -0
- package/test/fixtures/react-component.tsx +7 -6
- package/test/fixtures/react-strict.invalid.tsx +31 -0
- package/test/fixtures/react-strict.valid.tsx +76 -0
- package/test/fixtures/whitespaced-docstring.invalid.ts +10 -0
- package/test/fixtures/whitespaced-docstring.valid.ts +16 -0
- package/test/fixtures/whitespaced-members.invalid.ts +22 -0
- package/test/fixtures/whitespaced-members.valid.ts +13 -0
- package/test/fixtures/whitespaced-multiline.invalid.ts +8 -0
- package/test/fixtures/whitespaced-multiline.valid.ts +15 -0
- package/test/fixtures/whitespaced-types.valid.ts +5 -0
- package/test/fixtures/whitespaced.valid.ts +45 -0
- package/test/format-cases.mjs +13 -14
- package/test/test-runner.mjs +128 -47
package/rules.mjs
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export const rules = {
|
|
7
|
-
'multiline-comment-style':
|
|
8
|
-
'@stylistic/lines-around-comment':
|
|
7
|
+
'@stylistic/multiline-comment-style': [ 'warn', 'separate-lines', { checkJSDoc: false }],
|
|
8
|
+
'@stylistic/lines-around-comment': [ 'warn', {
|
|
9
9
|
beforeBlockComment: true,
|
|
10
10
|
beforeLineComment: false,
|
|
11
11
|
afterLineComment: false,
|
|
@@ -35,106 +35,106 @@ export const rules = {
|
|
|
35
35
|
'no-undef': [ 0 ],
|
|
36
36
|
'use-isnan': [ 'error' ],
|
|
37
37
|
'no-obj-calls': [ 'error' ],
|
|
38
|
-
'no-new-
|
|
38
|
+
'no-new-native-nonconstructor': [ 'error' ],
|
|
39
39
|
'no-func-assign': [ 'error' ],
|
|
40
40
|
'no-class-assign': [ 'error' ],
|
|
41
41
|
'no-array-constructor': [ 'error' ],
|
|
42
42
|
'omit/omit-unnecessary-parens-brackets': [ 'warn' ],
|
|
43
43
|
'no-inline-types/no-inline-multiline-types': [ 'warn' ],
|
|
44
|
-
'whitespaced/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
'whitespaced/aligned-assignments': [ 'warn', { alignMemberAssignments: false, alignTypes: true }],
|
|
45
|
+
'@stylistic/function-call-spacing': [ 'warn', 'never' ],
|
|
46
|
+
'@stylistic/computed-property-spacing': [ 'warn', 'never' ],
|
|
47
|
+
'@stylistic/brace-style': [ 'warn', 'stroustrup', { allowSingleLine: false }],
|
|
48
|
+
'@stylistic/comma-dangle': [ 'warn', 'only-multiline' ],
|
|
49
|
+
'@stylistic/comma-spacing': [ 'warn', { before: false, after: true }],
|
|
50
|
+
'@stylistic/comma-style': [ 'warn', 'last' ],
|
|
51
|
+
'@stylistic/key-spacing': [ 'warn', { beforeColon: false, afterColon: true, align: 'value' }],
|
|
52
|
+
'@stylistic/keyword-spacing': [ 'warn', { before: true, after: true }],
|
|
53
|
+
'@stylistic/object-property-newline': [ 'warn', { allowAllPropertiesOnSameLine: true }],
|
|
54
|
+
'@stylistic/max-len': [ 0, 400 ],
|
|
55
|
+
'@stylistic/no-tabs': [ 'warn' ],
|
|
56
|
+
'@stylistic/no-extra-parens': [ 'warn', 'all' ],
|
|
57
|
+
'@stylistic/no-multiple-empty-lines': [ 'warn', { max: 2, maxEOF: 0, maxBOF: 0 }],
|
|
58
|
+
'@stylistic/no-trailing-spaces': [ 'warn', { skipBlankLines: false, ignoreComments: false }],
|
|
59
|
+
'@stylistic/no-confusing-arrow': [ 0 ],
|
|
60
|
+
'@stylistic/no-whitespace-before-property': [ 'warn' ],
|
|
61
|
+
'@stylistic/space-in-parens': [ 'warn', 'never' ],
|
|
62
|
+
'@stylistic/space-infix-ops': [ 'warn', { int32Hint: false }],
|
|
63
|
+
'@stylistic/space-unary-ops': [ 'warn', { words: true, nonwords: false }],
|
|
64
|
+
'@stylistic/switch-colon-spacing': [ 'warn', { after: true, before: false }],
|
|
65
|
+
'@stylistic/template-curly-spacing': [ 'warn', 'never' ],
|
|
66
|
+
'@stylistic/wrap-iife': [ 'warn', 'inside' ],
|
|
67
|
+
'@stylistic/wrap-regex': [ 'warn' ],
|
|
68
|
+
'@stylistic/object-curly-spacing': [ 'warn', 'always', { arraysInObjects: false, objectsInObjects: false }],
|
|
69
|
+
'@stylistic/array-bracket-spacing': [ 'warn', 'always', { arraysInArrays: false, objectsInArrays: false }],
|
|
70
|
+
'@stylistic/new-parens': [ 'warn', 'always' ],
|
|
71
|
+
'@stylistic/operator-linebreak': [ 'warn', 'after', { overrides: { '?': 'before', ':': 'before' }}],
|
|
72
|
+
'@stylistic/quote-props': [ 'warn', 'consistent-as-needed', { keywords: false, unnecessary: true, numbers: false }],
|
|
73
|
+
'@stylistic/indent': [ 'warn', 2, { SwitchCase: 1, CallExpression: { arguments: 'first' }, offsetTernaryExpressions: false, flatTernaryExpressions: true }],
|
|
74
|
+
'@stylistic/arrow-spacing': [ 'warn' ],
|
|
75
|
+
'@stylistic/newline-per-chained-call': [ 'warn', { ignoreChainWithDepth: 2 }],
|
|
76
|
+
'@stylistic/lines-between-class-members': [ 'warn', 'always', { exceptAfterSingleLine: true }],
|
|
77
|
+
'@stylistic/one-var-declaration-per-line': [ 'warn', 'always' ],
|
|
78
|
+
'@stylistic/arrow-parens': [ 'warn', 'as-needed' ],
|
|
79
|
+
'@stylistic/dot-location': [ 'warn', 'property' ],
|
|
80
|
+
'@stylistic/eol-last': [ 'warn', 'always' ],
|
|
81
|
+
'@stylistic/multiline-ternary': [ 'warn', 'always-multiline' ],
|
|
82
|
+
'@stylistic/no-floating-decimal': [ 'warn' ],
|
|
83
|
+
'@stylistic/no-extra-semi': [ 'warn' ],
|
|
84
|
+
'@stylistic/semi-spacing': [ 'warn', { before: false, after: true }],
|
|
85
|
+
'@stylistic/semi-style': [ 'warn', 'last' ],
|
|
86
|
+
'@stylistic/semi': [ 'warn', 'never' ],
|
|
87
|
+
'@stylistic/space-before-function-paren': [ 'warn', { anonymous: 'always', named: 'always', asyncArrow: 'always' }],
|
|
88
|
+
'@stylistic/template-tag-spacing': [ 'warn', 'always' ],
|
|
89
|
+
'@stylistic/yield-star-spacing': [ 'warn', 'after' ],
|
|
90
|
+
'@stylistic/quotes': [ 'warn', 'single', { avoidEscape: true, allowTemplateLiterals: 'always' }],
|
|
91
|
+
'@stylistic/jsx-newline': [ 'warn', { prevent: true, allowMultilines: true }],
|
|
92
|
+
'@stylistic/jsx-equals-spacing': [ 'warn', 'never' ],
|
|
93
|
+
'@stylistic/jsx-max-props-per-line': [ 'warn', { maximum: 1, when: 'multiline' }],
|
|
94
|
+
'@stylistic/jsx-self-closing-comp': [ 'warn', { component: true, html: true }],
|
|
95
|
+
'@stylistic/jsx-one-expression-per-line': [ 'warn', { allow: 'non-jsx' }],
|
|
96
|
+
'@stylistic/jsx-tag-spacing': [ 'warn', { closingSlash: 'never', beforeSelfClosing: 'always', beforeClosing: 'never', afterOpening: 'never' }],
|
|
97
|
+
'@stylistic/jsx-closing-bracket-location': [ 'warn', 'after-props' ],
|
|
98
|
+
'@stylistic/jsx-closing-tag-location': [ 'warn', 'line-aligned' ],
|
|
99
|
+
'@stylistic/jsx-first-prop-new-line': [ 'warn', 'multiline' ],
|
|
100
|
+
'@stylistic/jsx-function-call-newline': [ 'warn', 'always' ],
|
|
101
|
+
'@stylistic/jsx-indent-props': [ 'warn', { indentMode: 2, ignoreTernaryOperator: true }],
|
|
102
|
+
'@stylistic/jsx-curly-spacing': [ 'warn', { when: 'always', spacing: { objectLiterals: 'never' }}],
|
|
103
|
+
'react/no-unescaped-entities': [ 'error', { forbid: [ '>', '}' ]}],
|
|
104
|
+
'react/jsx-uses-vars': [ 'error' ],
|
|
105
|
+
'react/jsx-uses-react': [ 'error' ],
|
|
106
|
+
'react/style-prop-object': [ 'error', { allow: []}],
|
|
107
|
+
'react/prefer-stateless-function': [ 'error', { ignorePureComponents: false }],
|
|
108
|
+
'react/no-invalid-html-attribute': [ 'error', []],
|
|
109
|
+
'react/hook-use-state': [ 'warn', { allowDestructuredState: true }],
|
|
110
|
+
'react/jsx-no-useless-fragment': [ 'warn', { allowExpressions: true }],
|
|
111
|
+
'react/jsx-no-target-blank': [ 'warn', { enforceDynamicLinks: 'always' }],
|
|
112
|
+
'react/jsx-no-constructed-context-values': [ 'warn' ],
|
|
113
|
+
'react/jsx-no-script-url': [ 'warn' ],
|
|
114
|
+
'react/jsx-no-comment-textnodes': [ 'warn' ],
|
|
115
|
+
'react/jsx-no-duplicate-props': [ 'warn' ],
|
|
116
|
+
'react/jsx-no-undef': [ 'warn' ],
|
|
117
|
+
'react/jsx-pascal-case': [ 'warn' ],
|
|
118
|
+
'react/jsx-curly-brace-presence': [ 'warn', { props: 'never', children: 'never' }],
|
|
119
|
+
'react/display-name': [ 'warn', { checkContextObjects: true }],
|
|
120
|
+
'react/no-unstable-nested-components': [ 'warn', { allowAsProps: true }],
|
|
121
|
+
'react/function-component-definition': [ 'warn', { namedComponents: 'arrow-function', unnamedComponents: 'arrow-function' }],
|
|
122
|
+
'react/jsx-no-leaked-render': [ 'warn', { validStrategies: [ 'ternary', 'coerce' ]}],
|
|
123
|
+
'react/jsx-sort-props': [ 'warn', {
|
|
124
|
+
callbacksLast: true,
|
|
125
|
+
shorthandFirst: true,
|
|
126
|
+
reservedFirst: true,
|
|
127
|
+
multiline: 'last',
|
|
128
|
+
noSortAlphabetically: true,
|
|
53
129
|
}],
|
|
54
|
-
'
|
|
55
|
-
'@stylistic/
|
|
56
|
-
'@stylistic/brace-style': [ 'warn', 'stroustrup', { allowSingleLine: false }],
|
|
57
|
-
'@stylistic/comma-dangle': [ 'warn', 'only-multiline' ],
|
|
58
|
-
'@stylistic/comma-spacing': [ 'warn', { before: false, after: true }],
|
|
59
|
-
'@stylistic/comma-style': [ 'warn', 'last' ],
|
|
60
|
-
'@stylistic/key-spacing': [ 'warn', { beforeColon: false, afterColon: true, align: 'value' }],
|
|
61
|
-
'@stylistic/keyword-spacing': [ 'warn', { before: true, after: true }],
|
|
62
|
-
'@stylistic/object-property-newline': [ 'warn', { allowAllPropertiesOnSameLine: true }],
|
|
63
|
-
'@stylistic/max-len': [ 0, 400 ],
|
|
64
|
-
'@stylistic/no-tabs': [ 'warn' ],
|
|
65
|
-
'@stylistic/no-extra-parens': [ 'warn', 'all' ],
|
|
66
|
-
'@stylistic/no-multiple-empty-lines': [ 'warn', { max: 2, maxEOF: 0, maxBOF: 0 }],
|
|
67
|
-
'@stylistic/no-trailing-spaces': [ 'warn', { skipBlankLines: false, ignoreComments: false }],
|
|
68
|
-
'@stylistic/no-confusing-arrow': [ 0 ],
|
|
69
|
-
'@stylistic/no-whitespace-before-property': [ 'warn' ],
|
|
70
|
-
'@stylistic/space-in-parens': [ 'warn', 'never' ],
|
|
71
|
-
'@stylistic/space-infix-ops': [ 'warn', { int32Hint: false }],
|
|
72
|
-
'@stylistic/space-unary-ops': [ 'warn', { words: true, nonwords: false }],
|
|
73
|
-
'@stylistic/switch-colon-spacing': [ 'warn', { after: true, before: false }],
|
|
74
|
-
'@stylistic/template-curly-spacing': [ 'warn', 'never' ],
|
|
75
|
-
'@stylistic/wrap-iife': [ 'warn', 'inside' ],
|
|
76
|
-
'@stylistic/wrap-regex': [ 'warn' ],
|
|
77
|
-
'@stylistic/object-curly-spacing': [ 'warn', 'always', { arraysInObjects: false, objectsInObjects: false }],
|
|
78
|
-
'@stylistic/array-bracket-spacing': [ 'warn', 'always', { arraysInArrays: false, objectsInArrays: false }],
|
|
79
|
-
'@stylistic/new-parens': [ 'warn', 'always' ],
|
|
80
|
-
'@stylistic/operator-linebreak': [ 'warn', 'after', { overrides: { '?': 'before', ':': 'before' }}],
|
|
81
|
-
'@stylistic/quote-props': [ 'warn', 'consistent-as-needed', { keywords: false, unnecessary: true, numbers: false }],
|
|
82
|
-
'@stylistic/indent': [ 'warn', 2, { SwitchCase: 1, CallExpression: { arguments: 'first' }, offsetTernaryExpressions: false, flatTernaryExpressions: true }],
|
|
83
|
-
'@stylistic/arrow-spacing': [ 'warn' ],
|
|
84
|
-
'@stylistic/newline-per-chained-call': [ 'warn', { ignoreChainWithDepth: 2 }],
|
|
85
|
-
'@stylistic/lines-between-class-members': [ 'warn', 'always', { exceptAfterSingleLine: true }],
|
|
86
|
-
'@stylistic/one-var-declaration-per-line': [ 'warn', 'always' ],
|
|
87
|
-
'@stylistic/arrow-parens': [ 'warn', 'as-needed' ],
|
|
88
|
-
'@stylistic/dot-location': [ 'warn', 'property' ],
|
|
89
|
-
'@stylistic/eol-last': [ 'warn', 'always' ],
|
|
90
|
-
'@stylistic/multiline-ternary': [ 'warn', 'always-multiline' ],
|
|
91
|
-
'@stylistic/no-floating-decimal': [ 'warn' ],
|
|
92
|
-
'@stylistic/no-extra-semi': [ 'warn' ],
|
|
93
|
-
'@stylistic/semi-spacing': [ 'warn', { before: false, after: true }],
|
|
94
|
-
'@stylistic/semi-style': [ 'warn', 'last' ],
|
|
95
|
-
'@stylistic/semi': [ 'warn', 'never' ],
|
|
96
|
-
'@stylistic/space-before-function-paren': [ 'warn', { anonymous: 'always', named: 'always', asyncArrow: 'always' }],
|
|
97
|
-
'@stylistic/template-tag-spacing': [ 'warn', 'always' ],
|
|
98
|
-
'@stylistic/yield-star-spacing': [ 'warn', 'after' ],
|
|
99
|
-
'@stylistic/quotes': [ 'warn', 'single', { avoidEscape: true, allowTemplateLiterals: 'always' }],
|
|
100
|
-
// JSX/React - Migrated to @stylistic plugin namespace (consistent)
|
|
101
|
-
'@stylistic/jsx-newline': [ 'warn', { prevent: true, allowMultilines: true }],
|
|
102
|
-
'@stylistic/jsx-props-no-multi-spaces': [ 'warn' ],
|
|
103
|
-
'@stylistic/jsx-equals-spacing': [ 'warn', 'never' ],
|
|
104
|
-
'@stylistic/jsx-max-props-per-line': [ 'warn', { maximum: 1, when: 'multiline' }],
|
|
105
|
-
'@stylistic/jsx-self-closing-comp': [ 'warn', { component: true, html: true }],
|
|
106
|
-
'@stylistic/jsx-one-expression-per-line': [ 'warn', { allow: 'non-jsx' }],
|
|
107
|
-
'@stylistic/jsx-tag-spacing': [ 'warn', { closingSlash: 'never', beforeSelfClosing: 'always', beforeClosing: 'never', afterOpening: 'never' }],
|
|
108
|
-
'@stylistic/jsx-closing-bracket-location': [ 'warn', 'after-props' ],
|
|
109
|
-
'@stylistic/jsx-closing-tag-location': [ 'warn', 'line-aligned' ],
|
|
110
|
-
'@stylistic/jsx-first-prop-new-line': [ 'warn', 'multiline' ],
|
|
111
|
-
'@stylistic/jsx-function-call-newline': [ 'warn', 'always' ],
|
|
112
|
-
'@stylistic/jsx-indent-props': [ 'warn', { indentMode: 2, ignoreTernaryOperator: true }],
|
|
113
|
-
'@stylistic/jsx-curly-spacing': [ 'warn', { when: 'always', spacing: { objectLiterals: 'never' }}],
|
|
114
|
-
'react/no-unescaped-entities': [ 'error', { forbid: [ '>', '}' ]}],
|
|
115
|
-
'react/jsx-uses-vars': [ 'error' ],
|
|
116
|
-
'react/jsx-uses-react': [ 'error' ],
|
|
117
|
-
'react/style-prop-object': [ 'error', { allow: []}],
|
|
118
|
-
'react/prefer-stateless-function': [ 'error', { ignorePureComponents: false }],
|
|
119
|
-
'react/no-invalid-html-attribute': [ 'error', []],
|
|
120
|
-
'react/hook-use-state': [ 'warn', { allowDestructuredState: true }],
|
|
121
|
-
'react/jsx-no-useless-fragment': [ 'warn', { allowExpressions: true }],
|
|
122
|
-
'react/jsx-no-target-blank': [ 'warn', { enforceDynamicLinks: 'always' }],
|
|
123
|
-
'react/jsx-no-constructed-context-values': [ 'warn' ],
|
|
124
|
-
'react/jsx-no-script-url': [ 'warn' ],
|
|
125
|
-
'react/jsx-no-comment-textnodes': [ 'warn' ],
|
|
126
|
-
'react/jsx-no-duplicate-props': [ 'warn' ],
|
|
127
|
-
'react/jsx-no-undef': [ 'warn' ],
|
|
128
|
-
'react/jsx-pascal-case': [ 'warn' ],
|
|
129
|
-
'react/jsx-curly-brace-presence': [ 'warn', { props: 'never', children: 'never' }],
|
|
130
|
-
'react/display-name': [ 'warn', { checkContextObjects: true }],
|
|
131
|
-
'react-hooks/exhaustive-deps': 0,
|
|
132
|
-
'@stylistic/no-multi-spaces': [ 'warn', {
|
|
130
|
+
'react-hooks/exhaustive-deps': 0,
|
|
131
|
+
'@stylistic/no-multi-spaces': [ 'warn', {
|
|
133
132
|
exceptions: {
|
|
134
|
-
Property:
|
|
135
|
-
TSTypeAnnotation:
|
|
136
|
-
VariableDeclarator:
|
|
137
|
-
|
|
133
|
+
Property: true,
|
|
134
|
+
TSTypeAnnotation: true,
|
|
135
|
+
VariableDeclarator: true,
|
|
136
|
+
AssignmentExpression: true,
|
|
137
|
+
ObjectExpression: false,
|
|
138
138
|
},
|
|
139
139
|
}],
|
|
140
140
|
'@stylistic/spaced-comment': [ 'warn', 'always', { markers: [ '/' ]}],
|
|
@@ -157,6 +157,12 @@ export const rules = {
|
|
|
157
157
|
{ blankLine: 'always', prev: [ 'block-like', 'block' ], next: [ 'multiline-expression', 'function', 'block-like', 'block' ]},
|
|
158
158
|
{ blankLine: 'any', prev: [ 'multiline-expression', 'function', 'block-like', 'block' ], next: [ 'multiline-expression', 'function', 'block-like', 'block' ]},
|
|
159
159
|
],
|
|
160
|
+
'react-strict/no-style-prop': [ 'warn' ],
|
|
161
|
+
'react-strict/no-nested-divs': [ 'warn' ],
|
|
162
|
+
'react-strict/no-complex-jsx-map': [ 'warn' ],
|
|
163
|
+
'react-strict/prefer-no-use-effect': [ 'warn' ],
|
|
164
|
+
'react-strict/no-jsx-value-calculations': [ 'warn' ],
|
|
165
|
+
'react-strict/jsx-prop-layout': [ 'warn' ],
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
export default rules
|
|
@@ -7,8 +7,8 @@ const testObject = {
|
|
|
7
7
|
name: 'test',
|
|
8
8
|
value: 42,
|
|
9
9
|
nested: {
|
|
10
|
-
property: 'value'
|
|
11
|
-
}
|
|
10
|
+
property: 'value',
|
|
11
|
+
},
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
|
|
@@ -27,8 +27,8 @@ const arrowFunction = (x, y) => {
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
const asyncFunction = async data => {
|
|
30
|
-
const response
|
|
31
|
-
const json
|
|
30
|
+
const response = await fetch('/api/data')
|
|
31
|
+
const json = await response.json()
|
|
32
32
|
|
|
33
33
|
return json
|
|
34
34
|
}
|
|
@@ -47,4 +47,5 @@ class TestClass {
|
|
|
47
47
|
|
|
48
48
|
export default basicFunction
|
|
49
49
|
|
|
50
|
+
|
|
50
51
|
export { TestClass, arrowFunction }
|
|
@@ -20,19 +20,19 @@ const complexObject = {
|
|
|
20
20
|
nested: {
|
|
21
21
|
deeply: {
|
|
22
22
|
buried: {
|
|
23
|
-
value: 'found'
|
|
24
|
-
}
|
|
25
|
-
}
|
|
23
|
+
value: 'found',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
26
|
},
|
|
27
27
|
array: [
|
|
28
28
|
{ id: 1, name: 'first' },
|
|
29
29
|
{ id: 2, name: 'second' },
|
|
30
|
-
{ id: 3, name: 'third' }
|
|
30
|
+
{ id: 3, name: 'third' },
|
|
31
31
|
],
|
|
32
32
|
methods: {
|
|
33
33
|
process: (data: unknown[]) => data.filter(Boolean),
|
|
34
|
-
validate: (input: string) => input.length > 0
|
|
35
|
-
}
|
|
34
|
+
validate: (input: string) => input.length > 0,
|
|
35
|
+
},
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
|
|
@@ -112,9 +112,11 @@ const destructuringExample = ({
|
|
|
112
112
|
displayName: name,
|
|
113
113
|
years: age,
|
|
114
114
|
place: city && country ? `${city}, ${country}` : 'Unknown',
|
|
115
|
-
metadata: rest
|
|
115
|
+
metadata: rest,
|
|
116
116
|
})
|
|
117
117
|
|
|
118
|
+
|
|
118
119
|
export type { ComplexType, GenericInterface }
|
|
119
120
|
|
|
121
|
+
|
|
120
122
|
export { GenericClass, complexFunction, destructuringExample, ternaryChain }
|
|
@@ -14,12 +14,18 @@ const complexTemplate = `
|
|
|
14
14
|
const regexPatterns = {
|
|
15
15
|
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
16
16
|
phone: /^\+?[\d\s-()]+$/,
|
|
17
|
-
url: /^https
|
|
17
|
+
url: /^https?:\/\/.+$/,
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
// Chained method calls
|
|
22
|
-
const chainedOperations = [
|
|
22
|
+
const chainedOperations = [
|
|
23
|
+
1,
|
|
24
|
+
2,
|
|
25
|
+
3,
|
|
26
|
+
4,
|
|
27
|
+
5,
|
|
28
|
+
]
|
|
23
29
|
.filter(x => x % 2 === 0)
|
|
24
30
|
.map(x => x * 2)
|
|
25
31
|
.reduce((acc, val) => acc + val, 0)
|
|
@@ -37,7 +43,7 @@ const dynamicKeys = {
|
|
|
37
43
|
yield 2
|
|
38
44
|
yield 3
|
|
39
45
|
},
|
|
40
|
-
[Symbol.toStringTag]: 'CustomObject'
|
|
46
|
+
[Symbol.toStringTag]: 'CustomObject',
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
|
|
@@ -47,7 +53,7 @@ const asyncErrorHandling = async () => {
|
|
|
47
53
|
const results = await Promise.all([
|
|
48
54
|
fetch('/api/users'),
|
|
49
55
|
fetch('/api/posts'),
|
|
50
|
-
fetch('/api/comments')
|
|
56
|
+
fetch('/api/comments'),
|
|
51
57
|
])
|
|
52
58
|
|
|
53
59
|
|
|
@@ -78,7 +84,7 @@ const arrowFunctionPatterns = {
|
|
|
78
84
|
const result = await processValue(x)
|
|
79
85
|
return result
|
|
80
86
|
},
|
|
81
|
-
destructured: ({ name, age }) => `${name} is ${age} years old
|
|
87
|
+
destructured: ({ name, age }) => `${name} is ${age} years old`,
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
|
|
@@ -103,8 +109,6 @@ const complexSwitch = (type, data) => {
|
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
|
|
106
|
-
// Export patterns
|
|
107
|
-
|
|
108
112
|
export {
|
|
109
113
|
complexTemplate,
|
|
110
114
|
regexPatterns,
|
|
@@ -116,4 +120,5 @@ export {
|
|
|
116
120
|
complexSwitch
|
|
117
121
|
}
|
|
118
122
|
|
|
123
|
+
|
|
119
124
|
export default complexCondition
|
|
@@ -15,9 +15,9 @@ const JSXFormattingTest = ({ items, onSelect, className }) => {
|
|
|
15
15
|
|
|
16
16
|
{/* Multi-line JSX with props */}
|
|
17
17
|
<button
|
|
18
|
-
onClick={ () => handleClick('test') }
|
|
19
18
|
disabled={ !items.length }
|
|
20
|
-
className="primary-button"
|
|
19
|
+
className="primary-button"
|
|
20
|
+
onClick={ () => handleClick('test') }>
|
|
21
21
|
Click me
|
|
22
22
|
</button>
|
|
23
23
|
|
|
@@ -31,8 +31,7 @@ const JSXFormattingTest = ({ items, onSelect, className }) => {
|
|
|
31
31
|
onClick={ () => handleClick(item.id) }>
|
|
32
32
|
<span>{item.name}</span>
|
|
33
33
|
|
|
34
|
-
{item.description
|
|
35
|
-
<small>{item.description}</small>
|
|
34
|
+
{item.description ? <small>{item.description}</small> : null
|
|
36
35
|
}
|
|
37
36
|
</li>
|
|
38
37
|
)}
|
|
@@ -132,6 +131,8 @@ const DataProvider = ({ children, data }) => {
|
|
|
132
131
|
return children(enhancedData)
|
|
133
132
|
}
|
|
134
133
|
|
|
134
|
+
|
|
135
135
|
export default JSXFormattingTest
|
|
136
136
|
|
|
137
|
+
|
|
137
138
|
export { withLoading, DataProvider }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// expect-warning: omit/omit-unnecessary-parens-brackets
|
|
2
|
+
const foo = ('bar')
|
|
3
|
+
|
|
4
|
+
// expect-warning: omit/omit-unnecessary-parens-brackets
|
|
5
|
+
function getValue () {
|
|
6
|
+
return ('value')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// expect-warning: omit/omit-unnecessary-parens-brackets
|
|
10
|
+
const arr = ([1, 2, 3])
|
|
11
|
+
|
|
12
|
+
export { foo, getValue, arr }
|
|
@@ -18,7 +18,7 @@ interface State {
|
|
|
18
18
|
const TestComponent: React.FC<Props> = ({ title, count = 0, onUpdate }) => {
|
|
19
19
|
const [ state, setState ] = useState<State>({
|
|
20
20
|
isLoading: false,
|
|
21
|
-
data: []
|
|
21
|
+
data: [],
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
|
|
@@ -27,13 +27,13 @@ const TestComponent: React.FC<Props> = ({ title, count = 0, onUpdate }) => {
|
|
|
27
27
|
setState(prev => ({ ...prev, isLoading: true }))
|
|
28
28
|
|
|
29
29
|
try {
|
|
30
|
-
const response
|
|
31
|
-
const data
|
|
30
|
+
const response = await fetch('/api/data')
|
|
31
|
+
const data = await response.json()
|
|
32
32
|
|
|
33
33
|
setState(prev => ({
|
|
34
34
|
...prev,
|
|
35
35
|
isLoading: false,
|
|
36
|
-
data
|
|
36
|
+
data,
|
|
37
37
|
}))
|
|
38
38
|
}
|
|
39
39
|
catch (error) {
|
|
@@ -69,8 +69,8 @@ const TestComponent: React.FC<Props> = ({ title, count = 0, onUpdate }) => {
|
|
|
69
69
|
|
|
70
70
|
<div className="content">
|
|
71
71
|
<button
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
disabled={ state.isLoading }
|
|
73
|
+
onClick={ () => handleClick(count + 1) }>
|
|
74
74
|
Click me ({count})
|
|
75
75
|
</button>
|
|
76
76
|
|
|
@@ -81,4 +81,5 @@ const TestComponent: React.FC<Props> = ({ title, count = 0, onUpdate }) => {
|
|
|
81
81
|
</div>
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
|
|
84
85
|
export default TestComponent
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
import React, { useState, useEffect } from 'react'
|
|
3
|
+
|
|
4
|
+
// expect-warning: react-strict/prefer-no-use-effect
|
|
5
|
+
const BadComponent = () => {
|
|
6
|
+
const [ data, setData ] = useState([])
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
fetch('/api').then(r => r.json())
|
|
9
|
+
.then(setData)
|
|
10
|
+
}, [])
|
|
11
|
+
|
|
12
|
+
return <div>
|
|
13
|
+
{/* expect-warning: react-strict/no-nested-divs */}
|
|
14
|
+
<div>
|
|
15
|
+
<p>Nested div is bad</p>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
{/* expect-warning: react-strict/no-style-prop */}
|
|
19
|
+
<span style={{ color: 'red' }}>styled inline</span>
|
|
20
|
+
|
|
21
|
+
{/* expect-warning: react-strict/no-complex-jsx-map */}
|
|
22
|
+
{data.map((item: string) => {
|
|
23
|
+
if (item === 'special')
|
|
24
|
+
return <strong key={ item }>Special</strong>
|
|
25
|
+
|
|
26
|
+
return <span key={ item }>{item}</span>
|
|
27
|
+
})}
|
|
28
|
+
</div>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default BadComponent
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React, { useState, useCallback, useMemo } from 'react'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
interface UserCardProps {
|
|
5
|
+
id: string
|
|
6
|
+
name: string
|
|
7
|
+
email: string
|
|
8
|
+
isActive: boolean
|
|
9
|
+
onSelect: (id: string) => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const UserCard: React.FC<UserCardProps> = ({ id, name, email, isActive, onSelect }) => {
|
|
14
|
+
const handleClick = useCallback(() => {
|
|
15
|
+
onSelect(id)
|
|
16
|
+
}, [ id, onSelect ])
|
|
17
|
+
|
|
18
|
+
const displayName = useMemo(() =>
|
|
19
|
+
isActive ? name : `${name} (inactive)`, [ isActive, name ])
|
|
20
|
+
|
|
21
|
+
return <article className="user-card">
|
|
22
|
+
<header>
|
|
23
|
+
<h3>{displayName}</h3>
|
|
24
|
+
</header>
|
|
25
|
+
|
|
26
|
+
<p>{email}</p>
|
|
27
|
+
|
|
28
|
+
<button
|
|
29
|
+
type="button"
|
|
30
|
+
onClick={ handleClick }>
|
|
31
|
+
Select
|
|
32
|
+
</button>
|
|
33
|
+
</article>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
interface UserListProps {
|
|
38
|
+
users: UserCardProps[]
|
|
39
|
+
onSelect: (id: string) => void
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
const UserListItem: React.FC<UserCardProps> = props =>
|
|
44
|
+
<UserCard { ...props } />
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const UserList: React.FC<UserListProps> = ({ users, onSelect }) => {
|
|
48
|
+
const [ filter, setFilter ] = useState('')
|
|
49
|
+
|
|
50
|
+
const filtered = useMemo(() =>
|
|
51
|
+
users.filter(u =>
|
|
52
|
+
u.name.toLowerCase().includes(filter.toLowerCase())), [ users, filter ])
|
|
53
|
+
|
|
54
|
+
const handleFilterChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
|
55
|
+
setFilter(e.target.value)
|
|
56
|
+
}, [])
|
|
57
|
+
|
|
58
|
+
return <section className="user-list">
|
|
59
|
+
<input
|
|
60
|
+
type="text"
|
|
61
|
+
placeholder="Filter users..."
|
|
62
|
+
value={ filter }
|
|
63
|
+
onChange={ handleFilterChange } />
|
|
64
|
+
|
|
65
|
+
<ul>
|
|
66
|
+
{filtered.map(user =>
|
|
67
|
+
<UserListItem
|
|
68
|
+
key={ user.id }
|
|
69
|
+
{ ...user }
|
|
70
|
+
onSelect={ onSelect } />)}
|
|
71
|
+
</ul>
|
|
72
|
+
</section>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
export default UserList
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// Returns the fixtures directory path.
|
|
5
|
+
function getFixturesDir (): string {
|
|
6
|
+
return path.join('/test', 'fixtures')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// Returns the config file path.
|
|
11
|
+
function getConfigPath (): string {
|
|
12
|
+
return path.join('/test', '../index.mjs')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export { getFixturesDir, getConfigPath }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
type ResultsType = { passed: number; failed: number; errors: string[] }
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestRunner {
|
|
8
|
+
fixturesDir: string
|
|
9
|
+
configPath: string
|
|
10
|
+
|
|
11
|
+
results: ResultsType
|
|
12
|
+
|
|
13
|
+
constructor () {
|
|
14
|
+
this.fixturesDir = path.join('/test', 'fixtures')
|
|
15
|
+
this.configPath = path.join('/test', '../index.mjs')
|
|
16
|
+
this.results = {
|
|
17
|
+
passed: 0,
|
|
18
|
+
failed: 0,
|
|
19
|
+
errors: [],
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|