@planfredapp/eslint-config 1.2.12 → 1.3.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/README.md +60 -22
- package/base.js +6 -7
- package/cypress.js +10 -0
- package/package.json +19 -14
- package/vue.js +5 -0
- package/eslint.config.js +0 -12
- package/vitest.config.js +0 -8
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @planfredapp/eslint-config
|
|
2
2
|
|
|
3
|
+
[View package on npm](https://www.npmjs.com/package/@planfredapp/eslint-config)
|
|
4
|
+
|
|
3
5
|
[](https://www.npmjs.com/package/@planfredapp/eslint-config)
|
|
4
6
|
[](LICENSE)
|
|
5
7
|
|
|
@@ -9,7 +11,7 @@ The package ships its plugins and parsers as dependencies. In consuming projects
|
|
|
9
11
|
|
|
10
12
|
## Requirements
|
|
11
13
|
|
|
12
|
-
- Node
|
|
14
|
+
- Node `>=26`
|
|
13
15
|
- `eslint >= 10`
|
|
14
16
|
- An ESM flat config file such as `eslint.config.js` or `eslint.config.mjs`
|
|
15
17
|
|
|
@@ -30,12 +32,16 @@ npm install --save-dev eslint @planfredapp/eslint-config
|
|
|
30
32
|
| Cypress | `@planfredapp/eslint-config/cypress` | Base config, `typescript-eslint` recommended rules, Cypress globals, `.only()` protection |
|
|
31
33
|
| Test | `@planfredapp/eslint-config/test` | Base config, Vitest recommended rules, test globals, `.only()` protection |
|
|
32
34
|
|
|
35
|
+
Every specialized entrypoint already includes the complete base config and adds its own rules on top without loosening base's options. Cypress swaps the core unused-code rules for typescript-eslint's versions with the same options; in `.ts` files, typescript-eslint also switches off the core rules that the TypeScript compiler covers, such as `no-undef`, so those checks depend on running `tsc` over the files (unreachable code is only a compiler error with `allowUnreachableCode: false`). Use the base entrypoint by itself for plain JavaScript, or select a specialized entrypoint when it applies to the whole project.
|
|
36
|
+
|
|
37
|
+
All entrypoints lint `.js`, `.mjs`, and `.cjs` files (`.cjs` is parsed as CommonJS). The Vue entrypoint adds `.vue` files. Only the Cypress entrypoint parses TypeScript; it uses the TypeScript parser for every file, so it doesn't reject TypeScript syntax in `.js` files or ESM syntax in `.cjs` files.
|
|
38
|
+
|
|
33
39
|
### Vue-Specific Assumptions
|
|
34
40
|
|
|
35
41
|
The Vue config contains a few project-structure assumptions:
|
|
36
42
|
|
|
37
43
|
- `src/**/*` must use `@` imports instead of relative imports
|
|
38
|
-
- `src/components/**/*` enforces component/file-name matching
|
|
44
|
+
- `src/components/**/*` enforces component/file-name matching and a `name` property on Options API components
|
|
39
45
|
- The config is intended for Vue 3 single-file components
|
|
40
46
|
|
|
41
47
|
## Usage
|
|
@@ -105,43 +111,75 @@ export default [
|
|
|
105
111
|
]
|
|
106
112
|
```
|
|
107
113
|
|
|
108
|
-
If
|
|
114
|
+
If one root `eslint.config.js` combines multiple specialized configs, apply the base config once and scope only each specialized config's additional entries with `defineConfig`'s `extends`:
|
|
109
115
|
|
|
110
116
|
```js
|
|
111
117
|
import baseConfig from '@planfredapp/eslint-config'
|
|
112
118
|
import cypressConfig from '@planfredapp/eslint-config/cypress'
|
|
113
119
|
import testConfig from '@planfredapp/eslint-config/test'
|
|
120
|
+
import vueConfig from '@planfredapp/eslint-config/vue'
|
|
121
|
+
import { defineConfig } from 'eslint/config'
|
|
114
122
|
|
|
115
|
-
const
|
|
116
|
-
...config,
|
|
117
|
-
files,
|
|
118
|
-
}))
|
|
123
|
+
const withoutBase = config => config.slice(baseConfig.length)
|
|
119
124
|
|
|
120
|
-
export default [
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
]
|
|
125
|
+
export default defineConfig([
|
|
126
|
+
baseConfig,
|
|
127
|
+
{
|
|
128
|
+
files: [ 'src/**/*.{js,vue}' ],
|
|
129
|
+
extends: [ withoutBase(vueConfig) ],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
files: [ 'cypress/**/*.{js,ts}' ],
|
|
133
|
+
extends: [ withoutBase(cypressConfig) ],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
files: [ 'test/**/*.js' ],
|
|
137
|
+
extends: [ withoutBase(testConfig) ],
|
|
138
|
+
},
|
|
139
|
+
])
|
|
125
140
|
```
|
|
126
141
|
|
|
142
|
+
This avoids applying the base entries more than once. The specialized entrypoints intentionally begin with the same base config entries. Widen the `files` patterns if those folders also hold `.mjs`, `.cjs`, or other file types.
|
|
143
|
+
|
|
144
|
+
Vue's path-scoped entries (`src/**` and `src/components/**`) are relative to the config's base path. For a Vue app in a subfolder, set `basePath` instead of prefixing `files`, or those entries silently match nothing: `{ basePath: 'apps/web', files: [ 'src/**/*.{js,vue}' ], extends: [ withoutBase(vueConfig) ] }`.
|
|
145
|
+
|
|
146
|
+
Don't scope entries by overwriting their `files` (`config.map(entry => ({ ...entry, files }))`). Some entries carry their own `files`, and overwriting them widens their scope: typescript-eslint's `.ts`-only overrides would switch off `no-undef` for Cypress `.js` files, and Vue's component-only rules would apply to every file. `extends` intersects the patterns instead.
|
|
147
|
+
|
|
127
148
|
## What The Base Config Enforces
|
|
128
149
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
-
|
|
132
|
-
- Trailing commas for multiline arrays, objects, imports, exports, and
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
150
|
+
Each item below is covered by a valid and an invalid example in [`test/configs.test.js`](test/configs.test.js).
|
|
151
|
+
|
|
152
|
+
- 2-space indentation, single quotes, no semicolons
|
|
153
|
+
- Trailing commas for multiline arrays, objects, imports, exports, function params, and call arguments; commas at the end of the line, never on a line of their own
|
|
154
|
+
- Spaces inside array brackets (`[ 1 ]`); arrays with 2+ items put each item on its own line
|
|
155
|
+
- Object literals with 2+ properties break after `{` and before `}`; inside, either all properties share one line or each gets its own line. Object destructuring may stay on one line; array destructuring follows the array rules
|
|
156
|
+
- A space before function parentheses (`function f ()`, `method ()`)
|
|
157
|
+
- A blank line between statements, including before `return`. Consecutive imports, consecutive `const`/`let`/`var` declarations, and consecutive expression statements may be adjacent; exported and function declarations are always separated
|
|
158
|
+
- Chains of 2+ calls put each call on its own line (`list.map(f).join()` → one call per line); a single call stays inline
|
|
159
|
+
- Imports in groups separated by a blank line: Node builtins and packages together, then relative paths, each group alphabetized. Without an import resolver, aliases and subpath imports (`@/`, `#`, `~/`) form a last group after relative paths; an `import-x/internal-regex` setting that marks them internal moves them between packages and relative paths
|
|
160
|
+
- `no-var`, `prefer-const`, `eqeqeq` (except `== null`), and a broad set of core correctness rules
|
|
161
|
+
- Unused function arguments, unused caught errors, and rest siblings used to omit properties are allowed; unused variables are not. An unused first parameter named `err` or `error` is reported, because `n/handle-callback-err` requires handling it
|
|
162
|
+
- Promise executor parameters named `resolve` and `reject`
|
|
163
|
+
|
|
164
|
+
### What The Vue Config Adds
|
|
165
|
+
|
|
166
|
+
- `@/` imports inside `src/` through the bundled `no-relative-import-paths` rule, with an autofix for relative imports
|
|
167
|
+
- Template expressions follow their own style: no spaces inside array brackets, arrays may stay on one line (`:items="[1, 2]"`), and multi-property objects put each property on its own line
|
|
168
|
+
- A blank line between sibling template elements
|
|
169
|
+
- Blocks ordered `<template>`, `<script>`, `<style>`, blank lines around multi-line component options, no `v-html`
|
|
170
|
+
|
|
171
|
+
## Package Contents
|
|
172
|
+
|
|
173
|
+
The npm package contains the four public config entrypoints plus the two internal custom-rule modules they use. Repository-only ESLint and Vitest config files are excluded from the published tarball.
|
|
136
174
|
|
|
137
175
|
## Development
|
|
138
176
|
|
|
139
177
|
```bash
|
|
140
|
-
|
|
141
|
-
|
|
178
|
+
pnpm lint
|
|
179
|
+
pnpm vitest run test/<relevant-spec>.test.js
|
|
142
180
|
```
|
|
143
181
|
|
|
144
|
-
More details are in [TESTING.md](TESTING.md). Release history is in [CHANGELOG.md](CHANGELOG.md).
|
|
182
|
+
Run the complete test suite through GitHub Actions. More details are in [TESTING.md](TESTING.md). Release history is in [CHANGELOG.md](CHANGELOG.md).
|
|
145
183
|
|
|
146
184
|
## License
|
|
147
185
|
|
package/base.js
CHANGED
|
@@ -17,7 +17,6 @@ export default [
|
|
|
17
17
|
stylistic: stylisticPlugin,
|
|
18
18
|
},
|
|
19
19
|
languageOptions: {
|
|
20
|
-
sourceType: 'module',
|
|
21
20
|
globals: {
|
|
22
21
|
...globals.node,
|
|
23
22
|
...globals.browser,
|
|
@@ -55,10 +54,6 @@ export default [
|
|
|
55
54
|
ignoreGlobals: true,
|
|
56
55
|
},
|
|
57
56
|
],
|
|
58
|
-
'comma-style': [
|
|
59
|
-
'error',
|
|
60
|
-
'last',
|
|
61
|
-
],
|
|
62
57
|
'constructor-super': 'error',
|
|
63
58
|
curly: [
|
|
64
59
|
'error',
|
|
@@ -136,10 +131,10 @@ export default [
|
|
|
136
131
|
'no-useless-catch': 'error',
|
|
137
132
|
'no-new': 'error',
|
|
138
133
|
'no-new-func': 'error',
|
|
139
|
-
'no-new-
|
|
140
|
-
'no-new-symbol': 'error',
|
|
134
|
+
'no-new-native-nonconstructor': 'error',
|
|
141
135
|
'no-new-wrappers': 'error',
|
|
142
136
|
'no-obj-calls': 'error',
|
|
137
|
+
'no-object-constructor': 'error',
|
|
143
138
|
'no-octal': 'error',
|
|
144
139
|
'no-octal-escape': 'error',
|
|
145
140
|
'no-proto': 'error',
|
|
@@ -352,6 +347,10 @@ export default [
|
|
|
352
347
|
after: true,
|
|
353
348
|
},
|
|
354
349
|
],
|
|
350
|
+
'stylistic/comma-style': [
|
|
351
|
+
'error',
|
|
352
|
+
'last',
|
|
353
|
+
],
|
|
355
354
|
'stylistic/computed-property-spacing': [
|
|
356
355
|
'error',
|
|
357
356
|
'never',
|
package/cypress.js
CHANGED
|
@@ -6,9 +6,17 @@ import tsEslint from 'typescript-eslint'
|
|
|
6
6
|
|
|
7
7
|
import baseConfig from './base.js'
|
|
8
8
|
|
|
9
|
+
// typescript-eslint replaces these core rules with its own versions, so carry over the base options
|
|
10
|
+
const baseRule = name => baseConfig.findLast(config => !config.files && config.rules?.[name]).rules[name]
|
|
11
|
+
|
|
9
12
|
export default [
|
|
10
13
|
...baseConfig,
|
|
11
14
|
...tsEslint.configs.recommended,
|
|
15
|
+
{
|
|
16
|
+
// typescript-eslint sets sourceType: 'module' for every file; restore ESLint's default for .cjs
|
|
17
|
+
files: [ '**/*.cjs' ],
|
|
18
|
+
languageOptions: { sourceType: 'commonjs' },
|
|
19
|
+
},
|
|
12
20
|
cypressPlugin.configs.recommended,
|
|
13
21
|
{
|
|
14
22
|
plugins: {
|
|
@@ -23,6 +31,8 @@ export default [
|
|
|
23
31
|
},
|
|
24
32
|
},
|
|
25
33
|
rules: {
|
|
34
|
+
'@typescript-eslint/no-unused-expressions': baseRule('no-unused-expressions'),
|
|
35
|
+
'@typescript-eslint/no-unused-vars': baseRule('no-unused-vars'),
|
|
26
36
|
'@typescript-eslint/no-require-imports': 'off',
|
|
27
37
|
'noOnlyTestsPlugin/no-only-tests': 'error',
|
|
28
38
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planfredapp/eslint-config",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Shared ESLint 10 configurations for Planfred
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Shared ESLint 10 flat configurations for Planfred projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
7
7
|
"eslint-config",
|
|
@@ -29,9 +29,14 @@
|
|
|
29
29
|
"./cypress": "./cypress.js",
|
|
30
30
|
"./test": "./test.js"
|
|
31
31
|
},
|
|
32
|
-
"main": "
|
|
32
|
+
"main": "./base.js",
|
|
33
33
|
"files": [
|
|
34
|
-
"
|
|
34
|
+
"base.js",
|
|
35
|
+
"cypress.js",
|
|
36
|
+
"no-relative-import-paths.js",
|
|
37
|
+
"promise-param-names.js",
|
|
38
|
+
"test.js",
|
|
39
|
+
"vue.js"
|
|
35
40
|
],
|
|
36
41
|
"engines": {
|
|
37
42
|
"node": ">=26"
|
|
@@ -39,20 +44,20 @@
|
|
|
39
44
|
"dependencies": {
|
|
40
45
|
"@eslint/js": "10.0.1",
|
|
41
46
|
"@stylistic/eslint-plugin": "5.10.0",
|
|
42
|
-
"@vitest/eslint-plugin": "1.6.
|
|
43
|
-
"eslint-plugin-cypress": "
|
|
44
|
-
"eslint-plugin-import-x": "4.
|
|
45
|
-
"eslint-plugin-n": "18.0
|
|
47
|
+
"@vitest/eslint-plugin": "1.6.28",
|
|
48
|
+
"eslint-plugin-cypress": "7.0.2",
|
|
49
|
+
"eslint-plugin-import-x": "4.17.1",
|
|
50
|
+
"eslint-plugin-n": "18.5.0",
|
|
46
51
|
"eslint-plugin-no-only-tests": "3.4.0",
|
|
47
|
-
"eslint-plugin-vue": "10.
|
|
48
|
-
"globals": "17.
|
|
49
|
-
"typescript-eslint": "8.
|
|
50
|
-
"vue-eslint-parser": "10.4.
|
|
52
|
+
"eslint-plugin-vue": "10.11.1",
|
|
53
|
+
"globals": "17.13.0",
|
|
54
|
+
"typescript-eslint": "8.72.0",
|
|
55
|
+
"vue-eslint-parser": "10.4.1"
|
|
51
56
|
},
|
|
52
57
|
"devDependencies": {
|
|
53
|
-
"eslint": "10.
|
|
58
|
+
"eslint": "10.13.0",
|
|
54
59
|
"typescript": "6.0.3",
|
|
55
|
-
"vitest": "
|
|
60
|
+
"vitest": "5.0.5"
|
|
56
61
|
},
|
|
57
62
|
"peerDependencies": {
|
|
58
63
|
"eslint": ">=10.0.0"
|
package/vue.js
CHANGED
|
@@ -7,6 +7,11 @@ import noRelativeImportPathsPlugin from './no-relative-import-paths.js'
|
|
|
7
7
|
export default [
|
|
8
8
|
...baseConfig,
|
|
9
9
|
...vuePlugin.configs['flat/recommended'],
|
|
10
|
+
{
|
|
11
|
+
// eslint-plugin-vue sets sourceType: 'module' for every file; restore ESLint's default for .cjs
|
|
12
|
+
files: [ '**/*.cjs' ],
|
|
13
|
+
languageOptions: { sourceType: 'commonjs' },
|
|
14
|
+
},
|
|
10
15
|
{
|
|
11
16
|
plugins: {
|
|
12
17
|
vue: vuePlugin,
|
package/eslint.config.js
DELETED