@itstandu/code-style 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.
@@ -0,0 +1,54 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Build outputs
7
+ dist/
8
+ build/
9
+ .next/
10
+ out/
11
+ .output/
12
+ .turbo/
13
+ .cache/
14
+
15
+ # Logs
16
+ *.log
17
+ npm-debug.log*
18
+ yarn-debug.log*
19
+ yarn-error.log*
20
+ pnpm-debug.log*
21
+ lerna-debug.log*
22
+
23
+ # Environment files
24
+ .env
25
+ .env.local
26
+ .env.*.local
27
+
28
+ # Test coverage
29
+ coverage/
30
+ .nyc_output/
31
+
32
+ # Lock files (optional - some teams prefer to format them)
33
+ # package-lock.json
34
+ # yarn.lock
35
+ # pnpm-lock.yaml
36
+
37
+ # Generated files
38
+ *.min.js
39
+ *.min.css
40
+
41
+ # OS files
42
+ .DS_Store
43
+ Thumbs.db
44
+
45
+ # IDE files
46
+ .vscode/
47
+ .idea/
48
+ *.swp
49
+ *.swo
50
+ *~
51
+
52
+ # Temporary files
53
+ *.tmp
54
+ *.temp
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # @itstandu/code-style
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@itstandu/code-style)](https://www.npmjs.com/package/@itstandu/code-style)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Production-ready shared ESLint + Prettier configuration library for JavaScript and TypeScript projects.
7
+
8
+ ## Features
9
+
10
+ - **ESLint v9** (Flat Config)
11
+ - **Prettier v3** with Tailwind CSS support
12
+ - Supports **JavaScript** and **TypeScript**
13
+ - Framework presets: **React**, **Next.js**, **Vue**, **Angular**, **NestJS**
14
+ - **Node.js** backend support
15
+ - Stable import sorting with `eslint-plugin-simple-import-sort`
16
+ - Auto-fix friendly rules
17
+ - **Complete Prettier coverage** - All formatting handled by Prettier, no conflicts with ESLint
18
+ - No style rules in ESLint (Prettier handles all formatting)
19
+ - Architecture rules via `eslint-plugin-boundaries` (opt-in only)
20
+
21
+ ## Installation
22
+
23
+ Choose your package manager:
24
+
25
+ ### npm
26
+
27
+ ```bash
28
+ npm install -D @itstandu/code-style
29
+ ```
30
+
31
+ ### pnpm
32
+
33
+ ```bash
34
+ pnpm add -D @itstandu/code-style
35
+ ```
36
+
37
+ ### yarn
38
+
39
+ ```bash
40
+ yarn add -D @itstandu/code-style
41
+ ```
42
+
43
+ ### bun
44
+
45
+ ```bash
46
+ bun add -d @itstandu/code-style
47
+ ```
48
+
49
+ **Note:** You do NOT need to install `eslint`, `prettier`, or any plugins separately. This package includes all dependencies.
50
+
51
+ ## Usage
52
+
53
+ ### ESLint
54
+
55
+ Create `eslint.config.js` (or `eslint.config.mjs`) in your project root:
56
+
57
+ #### Base Preset (Minimal)
58
+
59
+ ```javascript
60
+ const codeStyle = require('@itstandu/code-style')
61
+
62
+ module.exports = [
63
+ codeStyle.base,
64
+ codeStyle.typescript,
65
+ codeStyle.node
66
+ ]
67
+ ```
68
+
69
+ #### Recommended Preset (Better Safety)
70
+
71
+ ```javascript
72
+ const codeStyle = require('@itstandu/code-style')
73
+
74
+ module.exports = [
75
+ codeStyle.recommended,
76
+ codeStyle.typescript,
77
+ codeStyle.node
78
+ ]
79
+ ```
80
+
81
+ #### Strict Preset (Opt-in, includes boundaries)
82
+
83
+ ```javascript
84
+ const codeStyle = require('@itstandu/code-style')
85
+
86
+ module.exports = [
87
+ codeStyle.strict,
88
+ codeStyle.typescript,
89
+ codeStyle.node
90
+ ]
91
+ ```
92
+
93
+ ### Framework Presets
94
+
95
+ #### React
96
+
97
+ ```javascript
98
+ const codeStyle = require('@itstandu/code-style')
99
+
100
+ module.exports = [
101
+ codeStyle.recommended,
102
+ codeStyle.typescript,
103
+ codeStyle.react
104
+ ]
105
+ ```
106
+
107
+ #### Next.js
108
+
109
+ ```javascript
110
+ const codeStyle = require('@itstandu/code-style')
111
+
112
+ module.exports = [
113
+ codeStyle.recommended,
114
+ codeStyle.typescript,
115
+ codeStyle.next
116
+ ]
117
+ ```
118
+
119
+ #### Vue
120
+
121
+ ```javascript
122
+ const codeStyle = require('@itstandu/code-style')
123
+
124
+ module.exports = [
125
+ codeStyle.recommended,
126
+ codeStyle.vue
127
+ ]
128
+ ```
129
+
130
+ #### Angular
131
+
132
+ ```javascript
133
+ const codeStyle = require('@itstandu/code-style')
134
+
135
+ module.exports = [
136
+ codeStyle.recommended,
137
+ codeStyle.typescript,
138
+ codeStyle.angular
139
+ ]
140
+ ```
141
+
142
+ #### NestJS
143
+
144
+ ```javascript
145
+ const codeStyle = require('@itstandu/code-style')
146
+
147
+ module.exports = [
148
+ codeStyle.recommended,
149
+ codeStyle.typescript,
150
+ codeStyle.nest
151
+ ]
152
+ ```
153
+
154
+ ### Prettier
155
+
156
+ Create `.prettierrc.js` (or `.prettierrc.cjs`) in your project root:
157
+
158
+ ```javascript
159
+ module.exports = require('@itstandu/code-style/prettier')
160
+ ```
161
+
162
+ Or add to `package.json`:
163
+
164
+ ```json
165
+ {
166
+ "prettier": "@itstandu/code-style/prettier"
167
+ }
168
+ ```
169
+
170
+ **Optional:** Copy `.prettierignore` from this package to your project root to ignore common files:
171
+
172
+ ```bash
173
+ cp node_modules/@itstandu/code-style/.prettierignore .prettierignore
174
+ ```
175
+
176
+ ### Ensuring Consistent Formatting
177
+
178
+ This package ensures **100% Prettier coverage** for all formatting:
179
+
180
+ - ✅ All ESLint formatting rules are disabled via `eslint-config-prettier`
181
+ - ✅ React/JSX formatting rules are disabled (Prettier handles JSX)
182
+ - ✅ Vue template formatting rules are disabled (Prettier handles Vue)
183
+ - ✅ Comprehensive Prettier options cover all formatting scenarios
184
+ - ✅ Tailwind CSS class sorting is automatic (via `prettier-plugin-tailwindcss`)
185
+
186
+ ### Import Sorting Philosophy
187
+
188
+ **Critical Principle:**
189
+
190
+ > **Sort import → ESLint. Prettier TUYỆT ĐỐI không làm việc này.**
191
+
192
+ **Why ESLint, not Prettier?**
193
+
194
+ - **ESLint understands semantics**: side-effect imports, type vs value imports, module boundaries, aliases
195
+ - **Prettier only formats syntax**: whitespace, commas, line breaks — it doesn't understand import logic
196
+ - **Deterministic vs Context-aware**: Prettier aims for same input → same output. Import sorting needs context and grouping rules
197
+
198
+ **This package configuration:**
199
+
200
+ - ✅ **ESLint**: `simple-import-sort` handles all import sorting
201
+ - ✅ **Prettier**: Only formats code (whitespace, quotes, etc.) — **NO import sorting**
202
+ - ✅ **Exception**: Tailwind class sorting (string order, no logic impact)
203
+
204
+ **Result:** Clean separation of concerns, no conflicts, battle-tested approach.
205
+
206
+ **Important:** Make sure your editor/IDE:
207
+ - Uses Prettier as default formatter with `formatOnSave`
208
+ - Runs ESLint auto-fix on save (`source.fixAll.eslint`) for import sorting
209
+
210
+ ## Presets
211
+
212
+ ### `base`
213
+ Minimal, safe defaults. Good starting point.
214
+
215
+ ### `recommended`
216
+ Enhanced safety rules while remaining practical. Recommended for most projects.
217
+
218
+ ### `strict`
219
+ Opt-in preset with additional rules including:
220
+ - `eslint-plugin-unicorn` (code quality)
221
+ - `eslint-plugin-sonarjs` (bug detection)
222
+ - `eslint-plugin-boundaries` (architecture enforcement, disabled by default)
223
+
224
+ ## Available Configs
225
+
226
+ - `base` - Base ESLint configuration
227
+ - `javascript` - JavaScript support
228
+ - `typescript` - TypeScript support
229
+ - `node` - Node.js backend rules
230
+ - `react` - React framework rules
231
+ - `next` - Next.js framework rules
232
+ - `vue` - Vue framework rules
233
+ - `angular` - Angular framework rules
234
+ - `nest` - NestJS framework rules
235
+ - `recommended` - Recommended preset
236
+ - `strict` - Strict preset (opt-in)
237
+
238
+ ## Principles
239
+
240
+ - **Practical and stable** - Designed for long-term use (5-10 years)
241
+ - **Not over-opinionated** - Focuses on bugs, correctness, and maintainability
242
+ - **Auto-fix friendly** - Most rules are auto-fixable
243
+ - **No style rules in ESLint** - Prettier handles all formatting
244
+ - **Stable import sorting** - Uses `eslint-plugin-simple-import-sort` for predictable sorting
245
+ - **Architecture rules optional** - Boundaries enforcement is opt-in only
246
+
247
+ ## Requirements
248
+
249
+ - Node.js >= 18.0.0
250
+ - TypeScript >= 5.0.0 (peer dependency, optional for JS-only projects)
251
+
252
+ ## Contributing
253
+
254
+ Contributions are welcome! Please feel free to submit a Pull Request.
255
+
256
+ ## License
257
+
258
+ MIT
259
+
260
+ ---
261
+
262
+ Made with ❤️ by [@itstandu](https://github.com/itstandu)
@@ -0,0 +1,36 @@
1
+ const ts = require('./typescript')
2
+
3
+ module.exports = {
4
+ ...ts,
5
+ plugins: {
6
+ ...ts.plugins,
7
+ '@angular-eslint': require('@angular-eslint/eslint-plugin'),
8
+ '@angular-eslint/template': require('@angular-eslint/eslint-plugin-template')
9
+ },
10
+ rules: {
11
+ ...ts.rules,
12
+ '@angular-eslint/directive-selector': [
13
+ 'warn',
14
+ {
15
+ type: 'attribute',
16
+ prefix: 'app',
17
+ style: 'camelCase'
18
+ }
19
+ ],
20
+ '@angular-eslint/component-selector': [
21
+ 'warn',
22
+ {
23
+ type: 'element',
24
+ prefix: 'app',
25
+ style: 'kebab-case'
26
+ }
27
+ ],
28
+ '@angular-eslint/no-empty-lifecycle-method': 'warn',
29
+ '@angular-eslint/no-host-metadata-property': 'warn',
30
+ '@angular-eslint/no-input-rename': 'warn',
31
+ '@angular-eslint/no-output-on-prefix': 'warn',
32
+ '@angular-eslint/no-output-rename': 'warn',
33
+ '@angular-eslint/use-lifecycle-interface': 'warn',
34
+ '@angular-eslint/use-pipe-transform-interface': 'warn'
35
+ }
36
+ }
package/eslint/base.js ADDED
@@ -0,0 +1,73 @@
1
+ const prettierConfig = require('eslint-config-prettier')
2
+
3
+ module.exports = {
4
+ ignores: [
5
+ '**/node_modules/**',
6
+ '**/dist/**',
7
+ '**/build/**',
8
+ '**/.next/**',
9
+ '**/.output/**',
10
+ '**/.turbo/**',
11
+ '**/.cache/**',
12
+ '**/coverage/**'
13
+ ],
14
+ languageOptions: {
15
+ ecmaVersion: 'latest',
16
+ sourceType: 'module',
17
+ globals: {}
18
+ },
19
+ plugins: {
20
+ 'simple-import-sort': require('eslint-plugin-simple-import-sort'),
21
+ 'unused-imports': require('eslint-plugin-unused-imports'),
22
+ import: require('eslint-plugin-import')
23
+ },
24
+ settings: {
25
+ 'import/resolver': {
26
+ node: {
27
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs']
28
+ },
29
+ typescript: {
30
+ alwaysTryTypes: true
31
+ }
32
+ }
33
+ },
34
+ rules: {
35
+ ...prettierConfig.rules,
36
+
37
+ 'no-undef': 'error',
38
+ 'no-unreachable': 'error',
39
+ 'no-duplicate-imports': 'error',
40
+ 'no-console': 'warn',
41
+
42
+ 'no-var': 'error',
43
+ 'prefer-const': 'error',
44
+ 'no-shadow': 'off',
45
+
46
+ 'no-fallthrough': 'error',
47
+ 'no-empty': ['error', { allowEmptyCatch: true }],
48
+
49
+ 'no-async-promise-executor': 'error',
50
+
51
+ 'simple-import-sort/imports': [
52
+ 'error',
53
+ {
54
+ groups: [
55
+ ['^\\u0000'],
56
+ ['^node:'],
57
+ ['^@?\\w'],
58
+ ['^@/'],
59
+ ['^\\.\\.'],
60
+ ['^\\.']
61
+ ]
62
+ }
63
+ ],
64
+ 'simple-import-sort/exports': 'error',
65
+
66
+ 'unused-imports/no-unused-imports': 'error',
67
+ 'no-unused-vars': 'off',
68
+
69
+ 'import/first': 'error',
70
+ 'import/newline-after-import': 'error',
71
+ 'import/no-duplicates': 'error'
72
+ }
73
+ }
@@ -0,0 +1,5 @@
1
+ const base = require('./base')
2
+
3
+ module.exports = {
4
+ ...base
5
+ }
package/eslint/nest.js ADDED
@@ -0,0 +1,12 @@
1
+ const node = require('./node')
2
+
3
+ module.exports = {
4
+ ...node,
5
+ rules: {
6
+ ...node.rules,
7
+ '@typescript-eslint/explicit-function-return-type': 'off',
8
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
9
+ '@typescript-eslint/interface-name-prefix': 'off',
10
+ '@typescript-eslint/naming-convention': 'off'
11
+ }
12
+ }
package/eslint/next.js ADDED
@@ -0,0 +1,10 @@
1
+ const react = require('./react')
2
+
3
+ module.exports = {
4
+ ...react,
5
+ ignores: [
6
+ ...react.ignores,
7
+ '**/.next/**',
8
+ '**/out/**'
9
+ ]
10
+ }
package/eslint/node.js ADDED
@@ -0,0 +1,18 @@
1
+ const ts = require('./typescript')
2
+
3
+ module.exports = {
4
+ ...ts,
5
+ plugins: {
6
+ ...ts.plugins,
7
+ promise: require('eslint-plugin-promise'),
8
+ n: require('eslint-plugin-n')
9
+ },
10
+ rules: {
11
+ ...ts.rules,
12
+ 'n/no-process-exit': 'off',
13
+ 'n/no-missing-import': 'off',
14
+ 'promise/always-return': 'off',
15
+ 'promise/no-nesting': 'off',
16
+ 'promise/no-callback-in-promise': 'warn'
17
+ }
18
+ }
@@ -0,0 +1,101 @@
1
+ const ts = require('./typescript')
2
+
3
+ module.exports = {
4
+ ...ts,
5
+ languageOptions: {
6
+ ...ts.languageOptions,
7
+ parserOptions: {
8
+ ...ts.languageOptions.parserOptions,
9
+ ecmaFeatures: {
10
+ jsx: true
11
+ }
12
+ },
13
+ globals: {
14
+ ...ts.languageOptions.globals,
15
+ React: 'readonly',
16
+ JSX: 'readonly'
17
+ }
18
+ },
19
+ plugins: {
20
+ ...ts.plugins,
21
+ react: require('eslint-plugin-react'),
22
+ 'react-hooks': require('eslint-plugin-react-hooks'),
23
+ 'jsx-a11y': require('eslint-plugin-jsx-a11y')
24
+ },
25
+ settings: {
26
+ react: {
27
+ version: 'detect'
28
+ }
29
+ },
30
+ rules: {
31
+ ...ts.rules,
32
+ 'react/react-in-jsx-scope': 'off',
33
+ 'react/prop-types': 'off',
34
+ 'react/display-name': 'off',
35
+ 'react/jsx-uses-react': 'off',
36
+ 'react/jsx-uses-vars': 'error',
37
+ 'react/jsx-key': 'error',
38
+ 'react/jsx-no-duplicate-props': 'error',
39
+ 'react/jsx-no-undef': 'error',
40
+ 'react/jsx-no-useless-fragment': 'warn',
41
+ 'react/jsx-pascal-case': 'warn',
42
+ 'react/no-array-index-key': 'warn',
43
+ 'react/no-danger': 'warn',
44
+ 'react/no-deprecated': 'warn',
45
+ 'react/no-direct-mutation-state': 'error',
46
+ 'react/no-unescaped-entities': 'off',
47
+ 'react/no-unknown-property': 'error',
48
+ 'react/self-closing-comp': 'off',
49
+
50
+ 'react/jsx-boolean-value': 'off',
51
+ 'react/jsx-child-element-spacing': 'off',
52
+ 'react/jsx-closing-bracket-location': 'off',
53
+ 'react/jsx-closing-tag-location': 'off',
54
+ 'react/jsx-curly-brace-presence': 'off',
55
+ 'react/jsx-curly-newline': 'off',
56
+ 'react/jsx-curly-spacing': 'off',
57
+ 'react/jsx-equals-spacing': 'off',
58
+ 'react/jsx-first-prop-newline': 'off',
59
+ 'react/jsx-indent': 'off',
60
+ 'react/jsx-indent-props': 'off',
61
+ 'react/jsx-max-props-per-line': 'off',
62
+ 'react/jsx-newline': 'off',
63
+ 'react/jsx-one-expression-per-line': 'off',
64
+ 'react/jsx-props-no-multi-spaces': 'off',
65
+ 'react/jsx-quotes': 'off',
66
+ 'react/jsx-sort-props': 'off',
67
+ 'react/jsx-tag-spacing': 'off',
68
+ 'react/jsx-wrap-multilines': 'off',
69
+
70
+ 'react-hooks/rules-of-hooks': 'error',
71
+ 'react-hooks/exhaustive-deps': 'warn',
72
+
73
+ 'jsx-a11y/alt-text': 'warn',
74
+ 'jsx-a11y/anchor-has-content': 'warn',
75
+ 'jsx-a11y/anchor-is-valid': 'warn',
76
+ 'jsx-a11y/aria-activedescendant-has-tabindex': 'warn',
77
+ 'jsx-a11y/aria-props': 'warn',
78
+ 'jsx-a11y/aria-proptypes': 'warn',
79
+ 'jsx-a11y/aria-role': 'warn',
80
+ 'jsx-a11y/aria-unsupported-elements': 'warn',
81
+ 'jsx-a11y/click-events-have-key-events': 'warn',
82
+ 'jsx-a11y/heading-has-content': 'warn',
83
+ 'jsx-a11y/html-has-lang': 'warn',
84
+ 'jsx-a11y/img-redundant-alt': 'warn',
85
+ 'jsx-a11y/interactive-supports-focus': 'warn',
86
+ 'jsx-a11y/label-has-associated-control': 'warn',
87
+ 'jsx-a11y/mouse-events-have-key-events': 'warn',
88
+ 'jsx-a11y/no-access-key': 'warn',
89
+ 'jsx-a11y/no-autofocus': 'warn',
90
+ 'jsx-a11y/no-distracting-elements': 'warn',
91
+ 'jsx-a11y/no-interactive-element-to-noninteractive-role': 'warn',
92
+ 'jsx-a11y/no-noninteractive-element-interactions': 'warn',
93
+ 'jsx-a11y/no-noninteractive-element-to-interactive-role': 'warn',
94
+ 'jsx-a11y/no-redundant-roles': 'warn',
95
+ 'jsx-a11y/no-static-element-interactions': 'warn',
96
+ 'jsx-a11y/role-has-required-aria-props': 'warn',
97
+ 'jsx-a11y/role-supports-aria-props': 'warn',
98
+ 'jsx-a11y/scope': 'warn',
99
+ 'jsx-a11y/tabindex-no-positive': 'warn'
100
+ }
101
+ }
@@ -0,0 +1,29 @@
1
+ const base = require('./base')
2
+
3
+ module.exports = {
4
+ ...base,
5
+ rules: {
6
+ ...base.rules,
7
+ 'no-console': 'warn',
8
+ 'no-debugger': 'error',
9
+ 'no-alert': 'warn',
10
+ 'no-eval': 'error',
11
+ 'no-implied-eval': 'error',
12
+ 'no-new-func': 'error',
13
+ 'no-script-url': 'error',
14
+
15
+ 'prefer-arrow-callback': 'warn',
16
+ 'prefer-template': 'warn',
17
+ 'prefer-spread': 'warn',
18
+ 'prefer-rest-params': 'warn',
19
+
20
+ 'no-useless-return': 'warn',
21
+ 'no-useless-concat': 'warn',
22
+ 'no-useless-escape': 'warn',
23
+
24
+ 'import/no-unresolved': 'off',
25
+ 'import/no-cycle': 'warn',
26
+ 'import/no-self-import': 'error',
27
+ 'import/no-useless-path-segments': 'error'
28
+ }
29
+ }
@@ -0,0 +1,35 @@
1
+ const recommended = require('./recommended')
2
+
3
+ module.exports = {
4
+ ...recommended,
5
+ plugins: {
6
+ ...recommended.plugins,
7
+ boundaries: require('eslint-plugin-boundaries'),
8
+ unicorn: require('eslint-plugin-unicorn'),
9
+ sonarjs: require('eslint-plugin-sonarjs')
10
+ },
11
+ rules: {
12
+ ...recommended.rules,
13
+
14
+ 'unicorn/prefer-module': 'off',
15
+ 'unicorn/prefer-node-protocol': 'warn',
16
+ 'unicorn/no-array-callback-reference': 'warn',
17
+ 'unicorn/prefer-array-find': 'warn',
18
+ 'unicorn/prefer-array-some': 'warn',
19
+ 'unicorn/prefer-array-index-of': 'warn',
20
+ 'unicorn/prefer-string-starts-ends-with': 'warn',
21
+ 'unicorn/prefer-string-slice': 'warn',
22
+ 'unicorn/no-useless-undefined': 'warn',
23
+ 'unicorn/prefer-optional-catch-binding': 'warn',
24
+
25
+ 'sonarjs/cognitive-complexity': 'off',
26
+ 'sonarjs/no-duplicate-string': 'off',
27
+ 'sonarjs/no-small-switch': 'off',
28
+ 'sonarjs/prefer-immediate-return': 'warn',
29
+ 'sonarjs/prefer-single-boolean-return': 'warn',
30
+
31
+ 'boundaries/element-types': 'off',
32
+ 'boundaries/no-private': 'off',
33
+ 'boundaries/entry-point': 'off'
34
+ }
35
+ }
@@ -0,0 +1,36 @@
1
+ const base = require('./base')
2
+
3
+ module.exports = {
4
+ ...base,
5
+ languageOptions: {
6
+ ...base.languageOptions,
7
+ parser: require('@typescript-eslint/parser'),
8
+ parserOptions: {
9
+ ecmaVersion: 'latest',
10
+ sourceType: 'module',
11
+ project: true,
12
+ tsconfigRootDir: process.cwd()
13
+ }
14
+ },
15
+ plugins: {
16
+ ...base.plugins,
17
+ '@typescript-eslint': require('@typescript-eslint/eslint-plugin')
18
+ },
19
+ rules: {
20
+ ...base.rules,
21
+ 'no-unused-vars': 'off',
22
+ '@typescript-eslint/no-unused-vars': 'off',
23
+ '@typescript-eslint/no-floating-promises': 'error',
24
+ '@typescript-eslint/no-misused-promises': 'error',
25
+ '@typescript-eslint/consistent-type-imports': [
26
+ 'error',
27
+ { prefer: 'type-imports', fixStyle: 'inline-type-imports' }
28
+ ],
29
+ '@typescript-eslint/no-explicit-any': 'off',
30
+ '@typescript-eslint/explicit-function-return-type': 'off',
31
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
32
+ '@typescript-eslint/no-non-null-assertion': 'warn',
33
+ '@typescript-eslint/prefer-nullish-coalescing': 'warn',
34
+ '@typescript-eslint/prefer-optional-chain': 'warn'
35
+ }
36
+ }
package/eslint/vue.js ADDED
@@ -0,0 +1,101 @@
1
+ const base = require('./base')
2
+
3
+ module.exports = {
4
+ ...base,
5
+ languageOptions: {
6
+ ...base.languageOptions,
7
+ parser: require('vue-eslint-parser'),
8
+ parserOptions: {
9
+ parser: require('@typescript-eslint/parser'),
10
+ ecmaVersion: 'latest',
11
+ sourceType: 'module',
12
+ project: true
13
+ }
14
+ },
15
+ plugins: {
16
+ ...base.plugins,
17
+ vue: require('eslint-plugin-vue'),
18
+ '@typescript-eslint': require('@typescript-eslint/eslint-plugin')
19
+ },
20
+ rules: {
21
+ ...base.rules,
22
+ 'no-unused-vars': 'off',
23
+ '@typescript-eslint/no-unused-vars': 'off',
24
+ '@typescript-eslint/no-floating-promises': 'error',
25
+ '@typescript-eslint/no-misused-promises': 'error',
26
+ '@typescript-eslint/consistent-type-imports': [
27
+ 'error',
28
+ { prefer: 'type-imports', fixStyle: 'inline-type-imports' }
29
+ ],
30
+
31
+ 'vue/component-name-in-template-casing': ['warn', 'PascalCase'],
32
+ 'vue/component-definition-name-casing': ['warn', 'PascalCase'],
33
+ 'vue/custom-event-name-casing': 'warn',
34
+ 'vue/define-macros-order': 'warn',
35
+ 'vue/html-closing-bracket-newline': 'off',
36
+ 'vue/html-closing-bracket-spacing': 'off',
37
+ 'vue/html-end-tags': 'error',
38
+ 'vue/html-indent': 'off',
39
+ 'vue/html-quotes': 'off',
40
+ 'vue/html-self-closing': 'off',
41
+ 'vue/max-attributes-per-line': 'off',
42
+ 'vue/multiline-html-element-content-newline': 'off',
43
+ 'vue/mustache-interpolation-spacing': 'off',
44
+ 'vue/no-multi-spaces': 'off',
45
+ 'vue/no-spaces-around-equal-signs-in-attribute': 'off',
46
+ 'vue/no-template-shadow': 'warn',
47
+ 'vue/one-component-per-file': 'error',
48
+ 'vue/prop-name-casing': 'off',
49
+ 'vue/require-default-prop': 'off',
50
+ 'vue/require-explicit-emits': 'warn',
51
+ 'vue/require-prop-types': 'off',
52
+ 'vue/singleline-html-element-content-newline': 'off',
53
+ 'vue/v-bind-style': 'off',
54
+ 'vue/v-on-style': 'off',
55
+ 'vue/v-slot-style': 'off',
56
+ 'vue/attribute-hyphenation': 'off',
57
+ 'vue/component-tags-order': [
58
+ 'warn',
59
+ {
60
+ order: ['script', 'template', 'style']
61
+ }
62
+ ],
63
+ 'vue/define-emits-declaration': 'warn',
64
+ 'vue/define-props-declaration': 'warn',
65
+ 'vue/no-duplicate-attributes': 'error',
66
+ 'vue/no-empty-component-block': 'warn',
67
+ 'vue/no-multiple-object-in-class': 'error',
68
+ 'vue/no-multiple-slot-args': 'error',
69
+ 'vue/no-reserved-component-names': 'error',
70
+ 'vue/no-static-inline-styles': 'warn',
71
+ 'vue/no-template-key': 'error',
72
+ 'vue/no-textarea-mustache': 'error',
73
+ 'vue/no-unused-components': 'warn',
74
+ 'vue/no-unused-refs': 'warn',
75
+ 'vue/no-unused-v-else-if': 'error',
76
+ 'vue/no-use-v-if-with-v-for': 'error',
77
+ 'vue/no-useless-mustaches': 'warn',
78
+ 'vue/no-useless-v-bind': 'warn',
79
+ 'vue/prefer-separate-static-class': 'warn',
80
+ 'vue/prefer-true-attribute-shorthand': 'warn',
81
+ 'vue/require-toggle-inside-transition': 'error',
82
+ 'vue/use-v-on-exact': 'warn',
83
+ 'vue/valid-v-bind-sync': 'error',
84
+ 'vue/valid-v-bind': 'error',
85
+ 'vue/valid-v-cloak': 'error',
86
+ 'vue/valid-v-else-if': 'error',
87
+ 'vue/valid-v-else': 'error',
88
+ 'vue/valid-v-for': 'error',
89
+ 'vue/valid-v-html': 'error',
90
+ 'vue/valid-v-if': 'error',
91
+ 'vue/valid-v-is': 'error',
92
+ 'vue/valid-v-memo': 'error',
93
+ 'vue/valid-v-model': 'error',
94
+ 'vue/valid-v-on': 'error',
95
+ 'vue/valid-v-once': 'error',
96
+ 'vue/valid-v-pre': 'error',
97
+ 'vue/valid-v-show': 'error',
98
+ 'vue/valid-v-slot': 'error',
99
+ 'vue/valid-v-text': 'error'
100
+ }
101
+ }
package/index.js ADDED
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ base: require('./eslint/base'),
3
+ javascript: require('./eslint/javascript'),
4
+ typescript: require('./eslint/typescript'),
5
+ node: require('./eslint/node'),
6
+ react: require('./eslint/react'),
7
+ next: require('./eslint/next'),
8
+ vue: require('./eslint/vue'),
9
+ angular: require('./eslint/angular'),
10
+ nest: require('./eslint/nest'),
11
+ recommended: require('./eslint/recommended'),
12
+ strict: require('./eslint/strict')
13
+ }
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@itstandu/code-style",
3
+ "version": "0.1.0",
4
+ "description": "Production-ready shared ESLint + Prettier configuration for JavaScript and TypeScript projects",
5
+ "type": "commonjs",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./prettier": "./prettier/index.cjs"
10
+ },
11
+ "files": [
12
+ "eslint",
13
+ "prettier",
14
+ "index.js",
15
+ "README.md",
16
+ ".prettierignore"
17
+ ],
18
+ "keywords": [
19
+ "eslint",
20
+ "prettier",
21
+ "code-style",
22
+ "linting",
23
+ "formatting",
24
+ "typescript",
25
+ "javascript",
26
+ "react",
27
+ "vue",
28
+ "angular",
29
+ "nextjs",
30
+ "nestjs"
31
+ ],
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/itstandu/code-style.git"
35
+ },
36
+ "homepage": "https://github.com/itstandu/code-style#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/itstandu/code-style/issues"
39
+ },
40
+ "license": "MIT",
41
+ "engines": {
42
+ "node": ">=18.0.0"
43
+ },
44
+ "dependencies": {
45
+ "@angular-eslint/eslint-plugin": "*",
46
+ "@angular-eslint/eslint-plugin-template": "*",
47
+ "@angular-eslint/template-parser": "*",
48
+ "@typescript-eslint/eslint-plugin": "*",
49
+ "@typescript-eslint/parser": "*",
50
+ "eslint": "*",
51
+ "eslint-config-prettier": "*",
52
+ "eslint-plugin-boundaries": "*",
53
+ "eslint-plugin-import": "*",
54
+ "eslint-plugin-jsx-a11y": "*",
55
+ "eslint-plugin-n": "*",
56
+ "eslint-plugin-promise": "*",
57
+ "eslint-plugin-react": "*",
58
+ "eslint-plugin-react-hooks": "*",
59
+ "eslint-plugin-simple-import-sort": "*",
60
+ "eslint-plugin-sonarjs": "*",
61
+ "eslint-plugin-unicorn": "*",
62
+ "eslint-plugin-unused-imports": "*",
63
+ "eslint-plugin-vue": "*",
64
+ "@prettier/plugin-oxc": "*",
65
+ "prettier": "*",
66
+ "prettier-plugin-tailwindcss": "*",
67
+ "vue-eslint-parser": "*"
68
+ },
69
+ "peerDependencies": {
70
+ "typescript": ">=5.0.0"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "typescript": {
74
+ "optional": true
75
+ }
76
+ },
77
+ "scripts": {
78
+ "test": "echo \"Error: no test specified\" && exit 1"
79
+ }
80
+ }
@@ -0,0 +1,21 @@
1
+ module.exports = {
2
+ semi: false,
3
+ singleQuote: true,
4
+ trailingComma: 'all',
5
+ printWidth: 100,
6
+ tabWidth: 2,
7
+ useTabs: false,
8
+ arrowParens: 'always',
9
+ endOfLine: 'lf',
10
+ bracketSpacing: true,
11
+ bracketSameLine: false,
12
+ proseWrap: 'preserve',
13
+ htmlWhitespaceSensitivity: 'css',
14
+ insertPragma: false,
15
+ jsxSingleQuote: false,
16
+ quoteProps: 'as-needed',
17
+ requirePragma: false,
18
+ vueIndentScriptAndStyle: false,
19
+
20
+ plugins: ['@prettier/plugin-oxc', 'prettier-plugin-tailwindcss']
21
+ }