@santi020k/eslint-config-basic 0.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.
Files changed (140) hide show
  1. package/.agent/rules/context.md +78 -0
  2. package/.agent/rules/guidelines.md +124 -0
  3. package/.editorconfig +13 -0
  4. package/.env.example +8 -0
  5. package/.github/CODEOWNERS +2 -0
  6. package/.github/DISCUSSION_TEMPLATE/rfcs.yml +21 -0
  7. package/.github/DISCUSSION_TEMPLATE/technical-discussions.yml +21 -0
  8. package/.github/FUNDING.yml +2 -0
  9. package/.github/ISSUE_TEMPLATE/README.md +13 -0
  10. package/.github/ISSUE_TEMPLATE/bug_report.yml +69 -0
  11. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  12. package/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
  13. package/.github/ISSUE_TEMPLATE/question.yml +22 -0
  14. package/.github/SECURITY.md +12 -0
  15. package/.github/SPONSORSHIPS.md +27 -0
  16. package/.github/dependabot.yml +45 -0
  17. package/.github/labeler.yml +46 -0
  18. package/.github/pull_request_template.md +56 -0
  19. package/.github/workflows/assign-issues.yml +18 -0
  20. package/.github/workflows/audit.yml +22 -0
  21. package/.github/workflows/build.yml +29 -0
  22. package/.github/workflows/codeql.yml +40 -0
  23. package/.github/workflows/docs.yml +49 -0
  24. package/.github/workflows/labeler.yml +18 -0
  25. package/.github/workflows/publish.yml +24 -0
  26. package/.github/workflows/release.yml +35 -0
  27. package/.github/workflows/size-check.yml +23 -0
  28. package/.github/workflows/stale.yml +31 -0
  29. package/.nvmrc +1 -0
  30. package/.vscode/extensions.json +10 -0
  31. package/.vscode/settings.json +55 -0
  32. package/CHANGELOG.md +16 -0
  33. package/CONTRIBUTING.md +194 -0
  34. package/DEVELOPMENT.md +4 -0
  35. package/LICENSE +21 -0
  36. package/README.md +275 -0
  37. package/config/.husky/commit-msg +9 -0
  38. package/config/.husky/pre-commit +1 -0
  39. package/config/.husky/pre-push +1 -0
  40. package/config/.husky/prepare-commit-msg +1 -0
  41. package/cspell.config.yaml +2 -0
  42. package/eslint.config.js +21 -0
  43. package/llms.txt +72 -0
  44. package/package.json +61 -0
  45. package/packages/astro/README.md +13 -0
  46. package/packages/astro/package.json +45 -0
  47. package/packages/astro/src/ambient.d.ts +10 -0
  48. package/packages/astro/src/index.ts +18 -0
  49. package/packages/astro/src/rules.ts +29 -0
  50. package/packages/astro/tsconfig.json +9 -0
  51. package/packages/astro/tsup.config.ts +11 -0
  52. package/packages/basic/README.md +33 -0
  53. package/packages/basic/package.json +55 -0
  54. package/packages/basic/src/index.ts +110 -0
  55. package/packages/basic/tsconfig.json +9 -0
  56. package/packages/basic/tsup.config.ts +18 -0
  57. package/packages/core/README.md +14 -0
  58. package/packages/core/index.ts +14 -0
  59. package/packages/core/package.json +61 -0
  60. package/packages/core/src/ambient.d.ts +61 -0
  61. package/packages/core/src/index.ts +75 -0
  62. package/packages/core/src/rules.ts +157 -0
  63. package/packages/core/src/settings/gitignore.ts +10 -0
  64. package/packages/core/src/settings/index.ts +1 -0
  65. package/packages/core/src/types.ts +57 -0
  66. package/packages/core/src/utils/index.ts +28 -0
  67. package/packages/core/tsconfig.json +9 -0
  68. package/packages/core/tsup.config.ts +10 -0
  69. package/packages/expo/README.md +13 -0
  70. package/packages/expo/package.json +48 -0
  71. package/packages/expo/src/ambient.d.ts +3 -0
  72. package/packages/expo/src/index.ts +39 -0
  73. package/packages/expo/tsconfig.json +9 -0
  74. package/packages/expo/tsup.config.ts +11 -0
  75. package/packages/nest/package.json +45 -0
  76. package/packages/nest/src/ambient.d.ts +14 -0
  77. package/packages/nest/src/index.ts +20 -0
  78. package/packages/nest/src/rules.ts +15 -0
  79. package/packages/nest/tsconfig.json +9 -0
  80. package/packages/nest/tsup.config.ts +11 -0
  81. package/packages/next/README.md +13 -0
  82. package/packages/next/package.json +47 -0
  83. package/packages/next/src/index.ts +31 -0
  84. package/packages/next/src/rules.ts +16 -0
  85. package/packages/next/tsconfig.json +9 -0
  86. package/packages/next/tsup.config.ts +10 -0
  87. package/packages/optionals/README.md +18 -0
  88. package/packages/optionals/package.json +55 -0
  89. package/packages/optionals/src/ambient.d.ts +25 -0
  90. package/packages/optionals/src/cspell.ts +14 -0
  91. package/packages/optionals/src/i18next.ts +19 -0
  92. package/packages/optionals/src/index.ts +8 -0
  93. package/packages/optionals/src/markdown.ts +66 -0
  94. package/packages/optionals/src/mdx.ts +40 -0
  95. package/packages/optionals/src/stencil.ts +48 -0
  96. package/packages/optionals/src/tailwind.ts +11 -0
  97. package/packages/optionals/src/vitest.ts +61 -0
  98. package/packages/optionals/tsconfig.json +9 -0
  99. package/packages/optionals/tsup.config.ts +11 -0
  100. package/packages/playground/README.md +14 -0
  101. package/packages/playground/package.json +17 -0
  102. package/packages/playground/src/astro/eslint.config.js +4 -0
  103. package/packages/playground/src/js/eslint.config.js +4 -0
  104. package/packages/playground/src/js/index.test.js +63 -0
  105. package/packages/playground/src/mdx/eslint.config.js +4 -0
  106. package/packages/playground/src/mdx/index.mdx +115 -0
  107. package/packages/playground/src/react/eslint.config.js +4 -0
  108. package/packages/playground/src/react/index.test.jsx +130 -0
  109. package/packages/playground/src/ts/eslint.config.js +4 -0
  110. package/packages/playground/src/ts/index.test.ts +61 -0
  111. package/packages/playground/src/ts/tsconfig.json +3 -0
  112. package/packages/playground/tsconfig.json +9 -0
  113. package/packages/react/README.md +14 -0
  114. package/packages/react/index.ts +26 -0
  115. package/packages/react/package.json +49 -0
  116. package/packages/react/src/ambient.d.ts +23 -0
  117. package/packages/react/src/index.ts +52 -0
  118. package/packages/react/src/rules.ts +47 -0
  119. package/packages/react/tsconfig.json +9 -0
  120. package/packages/react/tsup.config.ts +10 -0
  121. package/packages/tests/README.md +17 -0
  122. package/packages/tests/package.json +21 -0
  123. package/packages/tests/src/__snapshots__/snapshots.test.ts.snap +654 -0
  124. package/packages/tests/src/composition.test.ts +171 -0
  125. package/packages/tests/src/configs.test.ts +118 -0
  126. package/packages/tests/src/rules.test.ts +60 -0
  127. package/packages/tests/src/snapshots.test.ts +126 -0
  128. package/packages/tests/tsconfig.json +10 -0
  129. package/packages/tests/vitest.config.ts +8 -0
  130. package/packages/typescript/README.md +14 -0
  131. package/packages/typescript/package.json +47 -0
  132. package/packages/typescript/src/index.ts +32 -0
  133. package/packages/typescript/src/rules.ts +36 -0
  134. package/packages/typescript/tsconfig.json +9 -0
  135. package/packages/typescript/tsup.config.ts +10 -0
  136. package/tsconfig.base.json +20 -0
  137. package/tsconfig.docs.json +18 -0
  138. package/turbo.json +19 -0
  139. package/typedoc.config.mjs +25 -0
  140. package/typedoc.markdown.mjs +26 -0
@@ -0,0 +1,48 @@
1
+ import { fixupPluginRules } from '@eslint/compat'
2
+ import stencilPlugin from '@stencil-community/eslint-plugin'
3
+ import type { TSESLint } from '@typescript-eslint/utils'
4
+
5
+ /**
6
+ * Stencil ESLint configuration
7
+ * Enforces best practices for Stencil.js components
8
+ */
9
+ export const stencil: TSESLint.FlatConfig.ConfigArray = [
10
+ {
11
+ name: 'optionals/stencil',
12
+ files: ['**/*.{tsx,ts}'],
13
+ plugins: {
14
+ '@stencil-community': fixupPluginRules({
15
+ rules: stencilPlugin.rules as Record<string, unknown>
16
+ } as Parameters<typeof fixupPluginRules>[0]) as unknown as TSESLint.FlatConfig.Plugin
17
+ },
18
+ rules: {
19
+ '@stencil-community/async-methods': 'error',
20
+ '@stencil-community/ban-prefix': ['error', ['stencil', 'stnl', 'st']],
21
+ '@stencil-community/decorators-context': 'error',
22
+ '@stencil-community/decorators-style': [
23
+ 'error', {
24
+ prop: 'inline',
25
+ state: 'inline',
26
+ element: 'inline',
27
+ event: 'inline',
28
+ method: 'multiline',
29
+ watch: 'multiline',
30
+ listen: 'multiline'
31
+ }],
32
+ '@stencil-community/element-type': 'error',
33
+ '@stencil-community/host-data-deprecated': 'error',
34
+ '@stencil-community/methods-must-be-public': 'error',
35
+ '@stencil-community/no-unused-watch': 'error',
36
+ '@stencil-community/own-methods-must-be-private': 'error',
37
+ '@stencil-community/own-props-must-be-private': 'error',
38
+ '@stencil-community/prefer-vdom-listener': 'error',
39
+ '@stencil-community/props-must-be-public': 'error',
40
+ '@stencil-community/props-must-be-readonly': 'error',
41
+ '@stencil-community/render-returns-host': 'error',
42
+ '@stencil-community/required-jsdoc': 'error',
43
+ '@stencil-community/reserved-member-names': 'error',
44
+ '@stencil-community/single-export': 'error',
45
+ '@stencil-community/strict-mutable': 'error'
46
+ }
47
+ }
48
+ ]
@@ -0,0 +1,11 @@
1
+ import pluginTailwind from 'eslint-plugin-tailwindcss'
2
+
3
+ import type { TSESLint } from '@typescript-eslint/utils'
4
+
5
+ /**
6
+ * Tailwind CSS ESLint configuration
7
+ * Enforces Tailwind CSS best practices
8
+ */
9
+ export const tailwind: TSESLint.FlatConfig.ConfigArray = [
10
+ ...(pluginTailwind.configs['flat/recommended'] as TSESLint.FlatConfig.ConfigArray)
11
+ ]
@@ -0,0 +1,61 @@
1
+ import testingLibrary from 'eslint-plugin-testing-library'
2
+ import pluginVitest from 'eslint-plugin-vitest'
3
+ import globals from 'globals'
4
+
5
+ import { fixupPluginRules } from '@eslint/compat'
6
+ import type { TSESLint } from '@typescript-eslint/utils'
7
+
8
+ /**
9
+ * Vitest ESLint configuration
10
+ * Provides linting rules for Vitest test files with best practices
11
+ */
12
+ export const vitest: TSESLint.FlatConfig.ConfigArray = [
13
+ {
14
+ name: 'optionals/vitest',
15
+ files: [
16
+ 'tests/**/*.{js,ts,jsx,tsx}',
17
+ '**/__tests__/**/*.{js,ts,jsx,tsx}',
18
+ '**/__mocks__/**/*.{js,ts,jsx,tsx}',
19
+ '**/test/**/*.{js,ts,jsx,tsx}',
20
+ '**/spec/**/*.{js,ts,jsx,tsx}',
21
+ '**/__spec__/**/*.{js,ts,jsx,tsx}',
22
+ '**/*.test.{js,ts,jsx,tsx}',
23
+ '**/*.spec.{js,ts,jsx,tsx}',
24
+ 'vitest.config.{js,ts}'
25
+ ],
26
+ languageOptions: {
27
+ globals: {
28
+ ...globals.node
29
+ }
30
+ },
31
+ plugins: {
32
+ vitest: pluginVitest,
33
+ 'testing-library': fixupPluginRules({
34
+ rules: testingLibrary.rules
35
+ } as unknown as Parameters<typeof fixupPluginRules>[0]) as unknown as TSESLint.FlatConfig.Plugin
36
+ },
37
+ rules: {
38
+ // Vitest recommended rules
39
+ ...pluginVitest.configs.recommended.rules,
40
+
41
+ // Best practice rules for testing
42
+ 'vitest/max-nested-describe': ['error', { max: 3 }],
43
+ 'vitest/expect-expect': [
44
+ 'error',
45
+ {
46
+ assertFunctionNames: ['expect', 'assert', 'should']
47
+ }
48
+ ],
49
+ 'vitest/no-identical-title': 'error',
50
+ 'vitest/no-focused-tests': 'error',
51
+ 'vitest/no-disabled-tests': 'warn',
52
+ 'vitest/prefer-to-be': 'warn',
53
+ 'vitest/prefer-to-have-length': 'warn',
54
+ 'vitest/valid-expect': 'error',
55
+
56
+ // Disable some rules that conflict with test patterns
57
+ '@typescript-eslint/no-explicit-any': 'off',
58
+ '@stylistic/padding-line-between-statements': 'off'
59
+ }
60
+ }
61
+ ]
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*.ts"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm'],
6
+ dts: true,
7
+ splitting: false,
8
+ sourcemap: true,
9
+ clean: true,
10
+ target: 'es2022'
11
+ })
@@ -0,0 +1,14 @@
1
+ # @santi020k/eslint-config-playground
2
+
3
+ Internal playground package for testing ESLint configurations against real files.
4
+
5
+ ## Description
6
+
7
+ This package contains various file types (React, Astro, MDX, TS) to verify that the ESLint rules are applied correctly in a real-world project structure.
8
+
9
+ ## Usage
10
+
11
+ Run linting on this package:
12
+ ```bash
13
+ npm run lint -w @santi020k/eslint-config-playground
14
+ ```
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@santi020k/eslint-config-playground",
3
+ "private": false,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "lint": "eslint .",
8
+ "lint:fix": "eslint . --fix"
9
+ },
10
+ "dependencies": {
11
+ "@santi020k/eslint-config-basic": "*",
12
+ "eslint": "^9.39.2",
13
+ "react": "^19.2.4",
14
+ "react-dom": "^19.2.4",
15
+ "typescript": "^5.9.3"
16
+ }
17
+ }
@@ -0,0 +1,4 @@
1
+ // @ts-check
2
+ import { ConfigOption, eslintConfig } from '../../dist/index.js'
3
+
4
+ export default eslintConfig({ config: [ConfigOption.Ts, ConfigOption.Astro] })
@@ -0,0 +1,4 @@
1
+ // @ts-check
2
+ import { eslintConfig } from '../../dist/index.js'
3
+
4
+ export default eslintConfig()
@@ -0,0 +1,63 @@
1
+ // test.js
2
+
3
+ // Function definitions to test various stylistic rules
4
+ const myFunction1 = () => {
5
+ const value = 10
6
+
7
+ if (value > 5) {
8
+ console.log('Value is greater than 5')
9
+ } else {
10
+ console.log('Value is 5 or less')
11
+ }
12
+
13
+ const result = value > 5 ? 'High' : 'Low'
14
+ const array = [1, 2, 3]
15
+
16
+ array.forEach(item => {
17
+ console.log(item)
18
+ })
19
+
20
+ return result
21
+ }
22
+
23
+ // Testing object and array formatting rules
24
+ const myObject = { a: 1, b: 2, c: 3 }
25
+ const myArray = [1, 2, 3, 4, 5]
26
+
27
+ // Testing padding and spacing rules
28
+ if (myArray.length > 0) {
29
+ console.log('Array is not empty')
30
+ }
31
+
32
+ const myFunction2 = param => !!param
33
+ // Testing invalid typeof comparison
34
+ const count = 0
35
+
36
+ if (typeof count === 'number') {
37
+ console.log('Count is a number')
38
+ }
39
+
40
+ // Testing unused variables
41
+ // eslint-disable-next-line no-unused-vars, unused-imports/no-unused-vars
42
+ const unusedVar = 'This is unused'
43
+
44
+ // Function with multiple return statements
45
+ // eslint-disable-next-line no-unused-vars, unused-imports/no-unused-vars
46
+ const complexFunction = () => {
47
+ if (count > 10) return 'High'
48
+
49
+ if (count < 0) return 'Low'
50
+
51
+ return 'Medium'
52
+ }
53
+
54
+ // Testing no-use-before-define
55
+ myDefinedFunction()
56
+
57
+ // eslint-disable-next-line func-style
58
+ function myDefinedFunction() {
59
+ console.log('Function called before definition')
60
+ }
61
+
62
+ // Export statement to test sorting
63
+ export { myFunction1, myFunction2, myObject, myArray }
@@ -0,0 +1,4 @@
1
+ // @ts-check
2
+ import { eslintConfig, OptionalOption } from '../../dist/index.js'
3
+
4
+ export default eslintConfig({ optionals: [OptionalOption.Mdx] })
@@ -0,0 +1,115 @@
1
+ ---
2
+ title: "The Ultimate MDX Example"
3
+ description: "A complete overview of MDX capabilities with lorem ipsum content"
4
+ author: "Santiago Ipsum"
5
+ tags: ["mdx", "example", "components"]
6
+ date: "2025-04-21"
7
+ ---
8
+
9
+ import { Button, Alert, FancyBox } from '../components/UI'
10
+ import Note from '../components/Note'
11
+ import Chart from '../components/Chart'
12
+
13
+ ## 🎢 Welcome to the MDX Playground
14
+
15
+ # Welcome to the MDX Playground 🎢
16
+
17
+ This is an **MDX** file. It's like Markdown, but on _steroids_ — powered by **JSX**. Let's explore all the features using some _Lorem Ipsum_.
18
+
19
+ ## 🧩 Embedded JSX Components
20
+
21
+ You can embed React components directly:
22
+
23
+ <Alert type="success">This is a success alert using a custom component!</Alert>
24
+
25
+ ## 📦 Importing Components
26
+
27
+ You can import components like `Note`, `FancyBox`, or even charts.
28
+
29
+ <Note>
30
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat.
31
+ </Note>
32
+
33
+ <FancyBox>
34
+ <h3>Fancy Box Title</h3>
35
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
36
+ </FancyBox>
37
+
38
+ ## 🖼️ Images
39
+
40
+ ![Placeholder](https://via.placeholder.com/300x200.png?text=Lorem+Ipsum)
41
+
42
+ ## 🧮 Code Blocks
43
+
44
+ ### JavaScript
45
+
46
+ ```js
47
+ const greet = name => `Hello, ${name}!`
48
+
49
+ greet('santi020k')
50
+ ```
51
+
52
+ ### Bash
53
+
54
+ ```bash
55
+ npm install @mdx-js/react
56
+ ```
57
+
58
+ ## 📊 Embedded Dynamic Chart
59
+
60
+ <Chart
61
+ title="Sample Chart"
62
+ data={[{ label: 'A', value: 10 }, { label: 'B', value: 20 }]}
63
+ />
64
+
65
+ ## 🔗 Links
66
+
67
+ Check out the [official MDX docs](https://mdxjs.com).
68
+
69
+ ## 🗒️ Lists and Tables
70
+
71
+ ### Bullet List
72
+
73
+ - Lorem ipsum
74
+ - Dolor sit amet
75
+ - Consectetur adipiscing
76
+
77
+ ### Numbered List
78
+
79
+ 1. First item
80
+ 2. Second item
81
+ 3. Third item
82
+
83
+ ### Table
84
+
85
+ | Feature | Supported |
86
+ |----------------|-----------|
87
+ | Markdown | ✅ |
88
+ | JSX | ✅ |
89
+ | Components | ✅ |
90
+ | Frontmatter | ✅ |
91
+
92
+ ## 🎉 Inline JSX
93
+
94
+ Here’s some inline JSX: `<span style={{ color: 'tomato' }}>Hello inline JSX!</span>`
95
+
96
+ ## 📌 Export Metadata
97
+
98
+ You can also export metadata if needed:
99
+
100
+ ```js
101
+ export const meta = {
102
+ layout: 'docs',
103
+ requiresAuth: false
104
+ }
105
+ ```
106
+
107
+ ---
108
+
109
+ ## 🧠 Conclusion
110
+
111
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque in odio vitae nunc luctus aliquet. MDX is powerful, flexible, and fun. Try it out in your next documentation or blog project!
112
+
113
+ ```
114
+
115
+ ---
@@ -0,0 +1,4 @@
1
+ // @ts-check
2
+ import { ConfigOption, eslintConfig } from '../../dist/index.js'
3
+
4
+ export default eslintConfig({ config: [ConfigOption.React] })
@@ -0,0 +1,130 @@
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useMemo,
5
+ useRef,
6
+ useState
7
+ } from 'react'
8
+
9
+ // Helper function to simulate fetching data
10
+ const fetchTodos = () => new Promise(resolve => {
11
+ setTimeout(() => {
12
+ resolve([
13
+ { id: 1, text: 'Learn React', completed: true },
14
+ {
15
+ id: 2,
16
+ text: 'Build a Todo App',
17
+ completed: false
18
+ },
19
+ { id: 3, text: 'Profit!', completed: false }
20
+ ])
21
+ }, 1000)
22
+ })
23
+
24
+ const TodoApp = () => {
25
+ const [todos, setTodos] = useState([])
26
+ const [filter, setFilter] = useState('all')
27
+ const [sortOrder, setSortOrder] = useState('asc')
28
+ const inputRef = useRef()
29
+
30
+ // Fetch todos when the component mounts
31
+ useEffect(() => {
32
+ const loadTodos = async () => {
33
+ const fetchedTodos = await fetchTodos()
34
+
35
+ setTodos(fetchedTodos)
36
+ }
37
+
38
+ loadTodos()
39
+ }, [todos])
40
+
41
+ // Handle adding a new todo
42
+ const addTodo = useCallback(() => {
43
+ const text = inputRef.current.value.trim()
44
+
45
+ if (text) {
46
+ setTodos(prevTodos => [
47
+ ...prevTodos,
48
+ { id: Date.now(), text, completed: false }
49
+ ])
50
+
51
+ inputRef.current.value = ''
52
+ }
53
+ }, [])
54
+
55
+ // Handle toggling the completion state of a todo
56
+ const toggleTodo = useCallback(id => {
57
+ setTodos(prevTodos => prevTodos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo))
58
+ }, [])
59
+
60
+ // Handle changing the filter state
61
+ const handleFilterChange = useCallback(event => {
62
+ setFilter(event.target.value)
63
+ }, [])
64
+
65
+ // Handle changing the sort order
66
+ const handleSortChange = useCallback(event => {
67
+ setSortOrder(event.target.value)
68
+ }, [])
69
+
70
+ // Filter and sort todos based on current state
71
+ const filteredAndSortedTodos = useMemo(() => {
72
+ const filteredTodos = todos.filter(todo => {
73
+ if (filter === 'completed') return todo.completed
74
+
75
+ if (filter === 'incomplete') return !todo.completed
76
+
77
+ return true
78
+ })
79
+
80
+ return filteredTodos.sort((a, b) => {
81
+ if (sortOrder === 'asc') return a.text.localeCompare(b.text)
82
+
83
+ return b.text.localeCompare(a.text)
84
+ })
85
+ }, [todos, filter, sortOrder])
86
+
87
+ return (
88
+ <div>
89
+ <h1>Todo List</h1>
90
+ <div>
91
+ <input ref={inputRef} type="text" placeholder="New todo" />
92
+ <button type="button" onClick={addTodo}>
93
+ Add Todo
94
+ </button>
95
+ </div>
96
+ <div>
97
+ <label>
98
+ Filter:
99
+ <select value={filter} onChange={handleFilterChange}>
100
+ <option value="all">All</option>
101
+ <option value="completed">Completed</option>
102
+ <option value="incomplete">Incomplete</option>
103
+ </select>
104
+ </label>
105
+ <label>
106
+ Sort:
107
+ <select value={sortOrder} onChange={handleSortChange}>
108
+ <option value="asc">Ascending</option>
109
+ <option value="desc">Descending</option>
110
+ </select>
111
+ </label>
112
+ </div>
113
+ <ul>
114
+ {filteredAndSortedTodos.map(todo => (
115
+ <li
116
+ key={todo.id}
117
+ style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
118
+ >
119
+ {todo.text}
120
+ <button type="button" onClick={() => toggleTodo(todo.id)}>
121
+ {todo.completed ? 'Undo' : 'Complete'}
122
+ </button>
123
+ </li>
124
+ ))}
125
+ </ul>
126
+ </div>
127
+ )
128
+ }
129
+
130
+ export default TodoApp
@@ -0,0 +1,4 @@
1
+ // @ts-check
2
+ import { ConfigOption, eslintConfig } from '../../dist/index.js'
3
+
4
+ export default eslintConfig({ config: [ConfigOption.Ts] })
@@ -0,0 +1,61 @@
1
+ // Function definitions to test various stylistic rules
2
+ const myFunction1 = (): string => {
3
+ const value = 10
4
+
5
+ if (value > 5) {
6
+ console.log('Value is greater than 5')
7
+ } else {
8
+ console.log('Value is 5 or less')
9
+ }
10
+
11
+ const result: string = value > 5 ? 'High' : 'Low'
12
+ const array: number[] = [1, 2, 3]
13
+
14
+ array.forEach(item => {
15
+ console.log(item)
16
+ })
17
+
18
+ return result
19
+ }
20
+
21
+ // Testing object and array formatting rules
22
+ const myObject: { a: number, b: number, c: number } = { a: 1, b: 2, c: 3 }
23
+ const myArray: number[] = [1, 2, 3, 4, 5]
24
+
25
+ // Testing padding and spacing rules
26
+ if (myArray.length > 0) {
27
+ console.log('Array is not empty')
28
+ }
29
+
30
+ const myFunction2 = (param: boolean): boolean => !!param
31
+ // Testing invalid typeof comparison
32
+ const count = 0
33
+
34
+ if (typeof count === 'number') {
35
+ console.log('Count is a number')
36
+ }
37
+
38
+ // Testing unused variables
39
+ // eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
40
+ const unusedVar = 'This is unused'
41
+
42
+ // Function with multiple return statements
43
+ // eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
44
+ const complexFunction = (): string => {
45
+ if (count > 10) return 'High'
46
+
47
+ if (count < 0) return 'Low'
48
+
49
+ return 'Medium'
50
+ }
51
+
52
+ // Testing no-use-before-define
53
+ myDefinedFunction()
54
+
55
+ // eslint-disable-next-line func-style
56
+ function myDefinedFunction(): void {
57
+ console.log('Function called before definition')
58
+ }
59
+
60
+ // Export statement to test sorting
61
+ export { myFunction1, myFunction2, myObject, myArray }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }
@@ -0,0 +1,14 @@
1
+ # @santi020k/eslint-config-react
2
+
3
+ React specific ESLint rules and configurations.
4
+
5
+ ## Description
6
+
7
+ This package provides:
8
+ - `eslint-plugin-react` recommended rules.
9
+ - `eslint-plugin-react-hooks` recommended rules.
10
+ - JSX accessibility rules.
11
+
12
+ ## Usage
13
+
14
+ This package is used automatically when `ConfigOption.React` is selected in the main configuration.
@@ -0,0 +1,26 @@
1
+ import jsxA11y from 'eslint-plugin-jsx-a11y'
2
+ import react from 'eslint-plugin-react'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+
5
+ import core from '@santi020k/eslint-config-core'
6
+
7
+ export default [
8
+ ...core,
9
+ {
10
+ plugins: {
11
+ react,
12
+ 'react-hooks': reactHooks,
13
+ 'jsx-a11y': jsxA11y
14
+ },
15
+ rules: {
16
+ ...react.configs.recommended.rules,
17
+ ...reactHooks.configs.recommended.rules,
18
+ ...jsxA11y.configs.recommended.rules
19
+ },
20
+ settings: {
21
+ react: {
22
+ version: 'detect'
23
+ }
24
+ }
25
+ }
26
+ ]
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@santi020k/eslint-config-react",
3
+ "version": "0.0.0",
4
+ "description": "React ESLint configuration with hooks and JSX rules",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch",
21
+ "clean": "rm -rf dist"
22
+ },
23
+ "peerDependencies": {
24
+ "eslint": "^9.0.0",
25
+ "react": ">=18.0.0"
26
+ },
27
+ "dependencies": {
28
+ "@santi020k/eslint-config-core": "*",
29
+ "@eslint/compat": "^2.0.2",
30
+ "eslint-plugin-react": "^7.37.5",
31
+ "eslint-plugin-react-hooks": "^7.0.1",
32
+ "globals": "^17.3.0"
33
+ },
34
+ "devDependencies": {
35
+ "@typescript-eslint/utils": "^8.54.0",
36
+ "tsup": "^8.5.1",
37
+ "typescript": "^5.9.3"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "license": "MIT",
43
+ "author": "santi020k",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/santi020k/eslint-config.git",
47
+ "directory": "packages/react"
48
+ }
49
+ }