@noxickon/codex 0.0.2 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Base ESLint configuration for TypeScript projects
3
+ * Framework-agnostic, provides core linting and sorting rules
4
+ * @param {Object} options - Configuration options
5
+ * @param {string} [options.tailwindEntryPoint='./src/tailwind.css'] - Path to Tailwind CSS entry point
6
+ * @param {boolean} [options.enableTailwind=true] - Enable Tailwind CSS plugin
7
+ * @returns {Array} ESLint flat config array
8
+ */
9
+
10
+ import js from '@eslint/js';
11
+ import betterTailwind from 'eslint-plugin-better-tailwindcss';
12
+ import perfectionist from 'eslint-plugin-perfectionist';
13
+ import sortDestructureKeys from 'eslint-plugin-sort-destructure-keys';
14
+ import unicorn from 'eslint-plugin-unicorn';
15
+ import unusedImports from 'eslint-plugin-unused-imports';
16
+ import globals from 'globals';
17
+ import tseslint from 'typescript-eslint';
18
+
19
+ export function createBaseConfig(options = {}) {
20
+ const { tailwindEntryPoint = './src/tailwind.css', enableTailwind = true } = options;
21
+
22
+ const baseConfig = [
23
+ {
24
+ ignores: ['dist', 'storybook-static', 'coverage', 'node_modules'],
25
+ },
26
+ {
27
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
28
+ files: ['**/*.{ts,tsx,js,jsx}'],
29
+ languageOptions: {
30
+ ecmaVersion: 2020,
31
+ globals: globals.browser,
32
+ },
33
+ plugins: {
34
+ perfectionist,
35
+ 'sort-destructure-keys': sortDestructureKeys,
36
+ unicorn,
37
+ 'unused-imports': unusedImports,
38
+ },
39
+ rules: {
40
+ // Unicorn - modern JS/TS best practices
41
+ ...unicorn.configs.recommended.rules,
42
+
43
+ // Unicorn Overrides - React-friendly but modern
44
+ 'unicorn/prevent-abbreviations': [
45
+ 'error',
46
+ {
47
+ checkFilenames: false,
48
+ allowList: {
49
+ // React Standards (Type names):
50
+ Props: true,
51
+ Ref: true,
52
+
53
+ // React Standards (runtime):
54
+ props: true,
55
+ ref: true,
56
+ prev: true,
57
+
58
+ // Standard Loop Counters:
59
+ i: true,
60
+ j: true,
61
+ k: true,
62
+
63
+ // Node.js/Backend Standards:
64
+ db: true,
65
+ env: true,
66
+ req: true,
67
+ res: true,
68
+
69
+ // Context/Function:
70
+ ctx: true,
71
+ fn: true,
72
+ args: true,
73
+ param: true,
74
+ params: true,
75
+ },
76
+ replacements: {
77
+ e: {
78
+ event: true,
79
+ },
80
+ evt: {
81
+ event: true,
82
+ },
83
+ },
84
+ },
85
+ ],
86
+ 'unicorn/catch-error-name': [
87
+ 'error',
88
+ {
89
+ name: 'error',
90
+ },
91
+ ],
92
+
93
+ // Too opinionated - disabled:
94
+ 'unicorn/no-null': 'off',
95
+ 'unicorn/no-array-reduce': 'off',
96
+ 'unicorn/no-array-for-each': 'off',
97
+ 'unicorn/prefer-top-level-await': 'off',
98
+ 'unicorn/filename-case': 'off',
99
+ 'unicorn/switch-case-braces': 'off',
100
+ 'unicorn/no-negated-condition': 'off',
101
+ 'unicorn/prefer-ternary': 'off',
102
+
103
+ // Modern best practices - as warnings:
104
+ 'unicorn/prefer-query-selector': 'warn',
105
+ 'unicorn/prefer-global-this': 'warn',
106
+ 'unicorn/import-style': 'off',
107
+ 'unicorn/no-useless-undefined': 'off',
108
+
109
+ // Perfectionist - auto-sorting
110
+ 'perfectionist/sort-interfaces': ['error'],
111
+ 'perfectionist/sort-object-types': ['error'],
112
+ 'perfectionist/sort-named-imports': ['error'],
113
+ 'perfectionist/sort-named-exports': ['error'],
114
+ 'perfectionist/sort-imports': [
115
+ 'error',
116
+ {
117
+ type: 'alphabetical',
118
+ order: 'asc',
119
+ ignoreCase: true,
120
+ newlinesBetween: 'always',
121
+ groups: [
122
+ ['builtin-type', 'builtin'],
123
+ 'frameworks',
124
+ ['external-type', 'external'],
125
+ ['internal-type', 'internal'],
126
+ ['parent-type', 'parent'],
127
+ ['sibling-type', 'sibling'],
128
+ ['index-type', 'index'],
129
+ ],
130
+ customGroups: [
131
+ {
132
+ groupName: 'frameworks',
133
+ elementNamePattern: ['^vite$', '^@vitejs/', '^react$', '^react-dom$'],
134
+ },
135
+ ],
136
+ },
137
+ ],
138
+
139
+ // Destructuring
140
+ 'sort-destructure-keys/sort-destructure-keys': ['error', { caseSensitive: true }],
141
+
142
+ // TypeScript
143
+ '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
144
+ '@typescript-eslint/no-unused-vars': 'off',
145
+
146
+ // Unused Imports - auto-cleanup
147
+ 'unused-imports/no-unused-imports': 'error',
148
+ 'unused-imports/no-unused-vars': [
149
+ 'warn',
150
+ {
151
+ argsIgnorePattern: '^_',
152
+ vars: 'all',
153
+ varsIgnorePattern: '^_',
154
+ args: 'after-used',
155
+ },
156
+ ],
157
+
158
+ // Import Restrictions - consistent absolute imports
159
+ 'no-restricted-imports': [
160
+ 'error',
161
+ {
162
+ patterns: [
163
+ {
164
+ group: ['../*'],
165
+ message:
166
+ 'Relative parent imports are not allowed. Use absolute imports with @ instead.',
167
+ },
168
+ ],
169
+ },
170
+ ],
171
+ },
172
+ },
173
+ ];
174
+
175
+ // Add Tailwind config if enabled
176
+ if (enableTailwind) {
177
+ baseConfig.push({
178
+ files: ['**/*.{ts,tsx,js,jsx}'],
179
+ plugins: {
180
+ 'better-tailwind': betterTailwind,
181
+ },
182
+ settings: {
183
+ 'better-tailwindcss': {
184
+ entryPoint: tailwindEntryPoint,
185
+ },
186
+ },
187
+ rules: {
188
+ 'better-tailwind/enforce-shorthand-classes': 'warn',
189
+ 'better-tailwind/no-unnecessary-whitespace': 'warn',
190
+ 'better-tailwind/no-duplicate-classes': 'warn',
191
+ 'better-tailwind/no-unregistered-classes': 'off',
192
+ },
193
+ });
194
+ }
195
+
196
+ return baseConfig;
197
+ }
@@ -1,226 +1,67 @@
1
- import js from '@eslint/js';
2
- import eslintConfigPrettier from 'eslint-config-prettier';
3
- import betterTailwind from 'eslint-plugin-better-tailwindcss';
1
+ /**
2
+ * React ESLint configuration extending base config
3
+ * @param {Object} options - Configuration options
4
+ * @param {string} [options.tailwindEntryPoint='./src/tailwind.css'] - Path to Tailwind CSS entry point
5
+ * @param {boolean} [options.enableTailwind=true] - Enable Tailwind CSS plugin
6
+ * @returns {Array} ESLint flat config array
7
+ */
8
+
4
9
  import jsxA11y from 'eslint-plugin-jsx-a11y';
5
10
  import perfectionist from 'eslint-plugin-perfectionist';
6
11
  import reactCompiler from 'eslint-plugin-react-compiler';
7
12
  import reactHooks from 'eslint-plugin-react-hooks';
8
13
  import reactRefresh from 'eslint-plugin-react-refresh';
9
- import sortDestructureKeys from 'eslint-plugin-sort-destructure-keys';
10
- import unicorn from 'eslint-plugin-unicorn';
11
- import unusedImports from 'eslint-plugin-unused-imports';
12
- import globals from 'globals';
13
- import tseslint from 'typescript-eslint';
14
-
15
- /**
16
- * Create ESLint config for React projects
17
- * @param {Object} options
18
- * @param {string} [options.tailwindEntryPoint] - Path to Tailwind CSS file (default: './src/tailwind.css')
19
- */
20
- export function createReactConfig({ tailwindEntryPoint = './src/tailwind.css' } = {}) {
21
- return [
22
- {
23
- ignores: ['dist', 'storybook-static', 'coverage', 'node_modules'],
24
- },
25
- js.configs.recommended,
26
- ...tseslint.configs.recommended,
27
- {
28
- files: ['**/*.{ts,tsx,js,jsx}'],
29
- languageOptions: {
30
- ecmaVersion: 2022,
31
- globals: globals.browser,
32
- },
33
- plugins: {
34
- 'better-tailwind': betterTailwind,
35
- 'jsx-a11y': jsxA11y,
36
- perfectionist,
37
- 'react-compiler': reactCompiler,
38
- 'react-hooks': reactHooks,
39
- 'react-refresh': reactRefresh,
40
- 'sort-destructure-keys': sortDestructureKeys,
41
- unicorn,
42
- 'unused-imports': unusedImports,
43
- },
44
- settings: {
45
- 'better-tailwindcss': {
46
- entryPoint: tailwindEntryPoint,
47
- },
48
- },
49
- rules: {
50
- // React
51
- ...reactHooks.configs.recommended.rules,
52
- 'react-compiler/react-compiler': 'error',
53
- 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
54
-
55
- // Tailwind - modern shorthand enforcement
56
- 'better-tailwind/enforce-shorthand-classes': 'warn',
57
- 'better-tailwind/no-unnecessary-whitespace': 'warn',
58
- 'better-tailwind/no-duplicate-classes': 'warn',
59
- 'better-tailwind/no-unregistered-classes': 'off',
60
-
61
- // Unicorn - modern JS/TS best practices
62
- ...unicorn.configs.recommended.rules,
63
-
64
- // Unicorn Overrides - React-friendly but modern
65
- 'unicorn/prevent-abbreviations': [
66
- 'error',
67
- {
68
- checkFilenames: false,
69
- allowList: {
70
- // React Standards (Type names):
71
- Props: true, // ButtonProps, OxButtonProps
72
- Ref: true, // ForwardRef types
73
-
74
- // React Standards (runtime):
75
- props: true, // function Component({ props })
76
- ref: true, // useRef, forwardRef
77
- prev: true, // setState((prev) => ...)
78
14
 
79
- // Standard Loop Counters:
80
- i: true,
81
- j: true,
82
- k: true,
15
+ import { createBaseConfig } from './base.config.js';
83
16
 
84
- // Node.js/Backend Standards:
85
- db: true,
86
- env: true,
87
- req: true,
88
- res: true,
17
+ export function createReactConfig(options = {}) {
18
+ const baseConfig = createBaseConfig(options);
89
19
 
90
- // Context/Function:
91
- ctx: true,
92
- fn: true,
93
- args: true,
94
- param: true,
95
- params: true,
20
+ const reactConfig = {
21
+ files: ['**/*.{ts,tsx,js,jsx}'],
22
+ plugins: {
23
+ 'jsx-a11y': jsxA11y,
24
+ perfectionist,
25
+ 'react-compiler': reactCompiler,
26
+ 'react-hooks': reactHooks,
27
+ 'react-refresh': reactRefresh,
28
+ },
29
+ rules: {
30
+ // React
31
+ ...reactHooks.configs.recommended.rules,
32
+ 'react-compiler/react-compiler': 'error',
33
+ 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
34
+
35
+ // Perfectionist - JSX Props sorting
36
+ 'perfectionist/sort-jsx-props': [
37
+ 'error',
38
+ {
39
+ type: 'alphabetical',
40
+ order: 'asc',
41
+ ignoreCase: true,
42
+ groups: ['id', 'unknown', 'callback'],
43
+ customGroups: [
44
+ {
45
+ groupName: 'id',
46
+ elementNamePattern: '^id$',
96
47
  },
97
- replacements: {
98
- // Important: Event handlers must be descriptive!
99
- e: {
100
- event: true,
101
- },
102
- evt: {
103
- event: true,
104
- },
48
+ {
49
+ groupName: 'callback',
50
+ elementNamePattern: '^on.+',
105
51
  },
106
- },
107
- ],
108
- 'unicorn/catch-error-name': [
109
- 'error',
110
- {
111
- name: 'error', // catch (error) instead of catch (err)
112
- },
113
- ],
114
-
115
- // Too opinionated - disabled:
116
- 'unicorn/no-null': 'off', // null has semantic meaning
117
- 'unicorn/no-array-reduce': 'off', // reduce is sometimes elegant
118
- 'unicorn/no-array-for-each': 'off', // forEach is fine
119
- 'unicorn/prefer-top-level-await': 'off', // Not supported everywhere
120
- 'unicorn/filename-case': 'off', // React = PascalCase
121
- 'unicorn/switch-case-braces': 'off', // Too strict
122
- 'unicorn/no-negated-condition': 'off', // Sometimes more readable
123
- 'unicorn/prefer-ternary': 'off', // if/else sometimes clearer
124
-
125
- // Modern best practices - as warnings instead of errors:
126
- 'unicorn/prefer-query-selector': 'warn', // querySelector is more modern
127
- 'unicorn/prefer-global-this': 'warn', // globalThis is ES2020 standard
128
- 'unicorn/import-style': 'off', // node:path vs path - both ok
129
- 'unicorn/no-useless-undefined': 'off', // Explicit undefined is sometimes clearer
130
-
131
- // Perfectionist - auto-sorting
132
- 'perfectionist/sort-interfaces': ['error'],
133
- 'perfectionist/sort-object-types': ['error'],
134
- 'perfectionist/sort-named-imports': ['error'],
135
- 'perfectionist/sort-named-exports': ['error'],
136
- 'perfectionist/sort-imports': [
137
- 'error',
138
- {
139
- type: 'alphabetical',
140
- order: 'asc',
141
- ignoreCase: true,
142
- newlinesBetween: 'always',
143
- groups: [
144
- ['builtin-type', 'builtin'],
145
- 'frameworks',
146
- ['external-type', 'external'],
147
- ['internal-type', 'internal'],
148
- ['parent-type', 'parent'],
149
- ['sibling-type', 'sibling'],
150
- ['index-type', 'index'],
151
- ],
152
- customGroups: [
153
- {
154
- groupName: 'frameworks',
155
- elementNamePattern: ['^vite$', '^@vitejs/', '^react$', '^react-dom$'],
156
- },
157
- ],
158
- },
159
- ],
160
- 'perfectionist/sort-jsx-props': [
161
- 'error',
162
- {
163
- type: 'alphabetical',
164
- order: 'asc',
165
- ignoreCase: true,
166
- groups: ['id', 'unknown', 'callback'],
167
- customGroups: [
168
- {
169
- groupName: 'id',
170
- elementNamePattern: '^id$',
171
- },
172
- {
173
- groupName: 'callback',
174
- elementNamePattern: '^on.+',
175
- },
176
- ],
177
- },
178
- ],
179
-
180
- // Destructuring
181
- 'sort-destructure-keys/sort-destructure-keys': ['error', { caseSensitive: true }],
182
-
183
- // TypeScript
184
- '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
185
- '@typescript-eslint/no-unused-vars': 'off',
186
-
187
- // Unused Imports - auto-cleanup
188
- 'unused-imports/no-unused-imports': 'error',
189
- 'unused-imports/no-unused-vars': [
190
- 'warn',
191
- {
192
- argsIgnorePattern: '^_',
193
- vars: 'all',
194
- varsIgnorePattern: '^_',
195
- args: 'after-used',
196
- },
197
- ],
198
-
199
- // Accessibility - important for UI library!
200
- 'jsx-a11y/alt-text': 'warn',
201
- 'jsx-a11y/aria-props': 'warn',
202
- 'jsx-a11y/aria-proptypes': 'warn',
203
- 'jsx-a11y/aria-unsupported-elements': 'warn',
204
- 'jsx-a11y/role-has-required-aria-props': 'warn',
205
- 'jsx-a11y/role-supports-aria-props': 'warn',
206
-
207
- // Import Restrictions - consistent absolute imports
208
- 'no-restricted-imports': [
209
- 'error',
210
- {
211
- patterns: [
212
- {
213
- group: ['../*'],
214
- message:
215
- 'Relative parent imports are not allowed. Use absolute imports with @ instead.',
216
- },
217
- ],
218
- },
219
- ],
220
- },
52
+ ],
53
+ },
54
+ ],
55
+
56
+ // Accessibility - important for UI library!
57
+ 'jsx-a11y/alt-text': 'warn',
58
+ 'jsx-a11y/aria-props': 'warn',
59
+ 'jsx-a11y/aria-proptypes': 'warn',
60
+ 'jsx-a11y/aria-unsupported-elements': 'warn',
61
+ 'jsx-a11y/role-has-required-aria-props': 'warn',
62
+ 'jsx-a11y/role-supports-aria-props': 'warn',
221
63
  },
222
- eslintConfigPrettier,
223
- ];
224
- }
64
+ };
225
65
 
226
- export default createReactConfig();
66
+ return [...baseConfig, reactConfig];
67
+ }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@noxickon/codex",
3
- "version": "0.0.2",
3
+ "version": "0.1.1",
4
4
  "author": "noxickon",
5
5
  "license": "MIT",
6
6
  "description": "Shared ESLint & Prettier configuration for noxickon projects",
7
7
  "type": "module",
8
8
  "exports": {
9
9
  "./prettier": "./prettier.config.js",
10
+ "./eslint/base": "./eslint/base.config.js",
10
11
  "./eslint/react": "./eslint/react.config.js"
11
12
  },
12
13
  "files": [
@@ -20,20 +21,36 @@
20
21
  ],
21
22
  "peerDependencies": {
22
23
  "eslint": "^9.0.0",
23
- "prettier": "^3.0.0"
24
- },
25
- "dependencies": {
26
- "@typescript-eslint/eslint-plugin": "^8.46.4",
27
- "@typescript-eslint/parser": "^8.46.4",
28
- "eslint-config-prettier": "^10.1.8",
29
- "eslint-plugin-better-tailwindcss": "^3.7.10",
30
- "eslint-plugin-jsx-a11y": "^6.10.2",
31
- "eslint-plugin-react": "^7.37.5",
32
- "eslint-plugin-react-compiler": "^19.1.0-rc.2",
33
- "eslint-plugin-react-hooks": "^7.0.1",
34
- "eslint-plugin-sort-destructure-keys": "^2.0.0",
24
+ "prettier": "^3.0.0",
25
+ "@eslint/js": "^9.0.0",
26
+ "typescript-eslint": "^8.0.0",
27
+ "globals": "^16.0.0",
35
28
  "eslint-plugin-unicorn": "^62.0.0",
36
- "prettier-plugin-tailwindcss": "^0.7.1",
37
- "typescript-eslint": "^8.46.4"
29
+ "eslint-plugin-perfectionist": "^4.0.0",
30
+ "eslint-plugin-sort-destructure-keys": "^2.0.0",
31
+ "eslint-plugin-unused-imports": "^4.0.0",
32
+ "eslint-plugin-better-tailwindcss": "^3.0.0",
33
+ "eslint-plugin-jsx-a11y": "^6.0.0",
34
+ "eslint-plugin-react-hooks": "^7.0.0",
35
+ "eslint-plugin-react-compiler": ">=19.0.0",
36
+ "eslint-plugin-react-refresh": "^0.4.0",
37
+ "prettier-plugin-tailwindcss": "^0.7.0"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "eslint-plugin-better-tailwindcss": {
41
+ "optional": true
42
+ },
43
+ "eslint-plugin-jsx-a11y": {
44
+ "optional": true
45
+ },
46
+ "eslint-plugin-react-hooks": {
47
+ "optional": true
48
+ },
49
+ "eslint-plugin-react-compiler": {
50
+ "optional": true
51
+ },
52
+ "eslint-plugin-react-refresh": {
53
+ "optional": true
54
+ }
38
55
  }
39
56
  }