@planfredapp/eslint-config 1.2.15 → 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 CHANGED
@@ -32,14 +32,16 @@ npm install --save-dev eslint @planfredapp/eslint-config
32
32
  | Cypress | `@planfredapp/eslint-config/cypress` | Base config, `typescript-eslint` recommended rules, Cypress globals, `.only()` protection |
33
33
  | Test | `@planfredapp/eslint-config/test` | Base config, Vitest recommended rules, test globals, `.only()` protection |
34
34
 
35
- Every specialized entrypoint already includes the complete base config. Use the base entrypoint by itself for plain JavaScript, or select a specialized entrypoint when it applies to the whole project.
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.
36
38
 
37
39
  ### Vue-Specific Assumptions
38
40
 
39
41
  The Vue config contains a few project-structure assumptions:
40
42
 
41
43
  - `src/**/*` must use `@` imports instead of relative imports
42
- - `src/components/**/*` enforces component/file-name matching
44
+ - `src/components/**/*` enforces component/file-name matching and a `name` property on Options API components
43
45
  - The config is intended for Vue 3 single-file components
44
46
 
45
47
  ## Usage
@@ -109,40 +111,62 @@ export default [
109
111
  ]
110
112
  ```
111
113
 
112
- If one root `eslint.config.js` combines multiple specialized configs, apply the base config once and scope only each specialized config's additional entries:
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`:
113
115
 
114
116
  ```js
115
117
  import baseConfig from '@planfredapp/eslint-config'
116
118
  import cypressConfig from '@planfredapp/eslint-config/cypress'
117
119
  import testConfig from '@planfredapp/eslint-config/test'
120
+ import vueConfig from '@planfredapp/eslint-config/vue'
121
+ import { defineConfig } from 'eslint/config'
118
122
 
119
123
  const withoutBase = config => config.slice(baseConfig.length)
120
- const scope = (config, files) => config.map(entry => ({
121
- ...entry,
122
- files,
123
- }))
124
124
 
125
- export default [
126
- ...baseConfig,
127
- ...scope(withoutBase(cypressConfig), [ 'cypress/**/*.{js,ts}' ]),
128
- ...scope(withoutBase(testConfig), [ 'test/**/*.{js,ts}' ]),
129
- ]
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
+ ])
130
140
  ```
131
141
 
132
- This avoids applying the base entries more than once. The specialized entrypoints intentionally begin with the same base config entries.
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.
133
147
 
134
148
  ## What The Base Config Enforces
135
149
 
136
- - 2-space indentation
137
- - Single quotes
138
- - No semicolons
139
- - Trailing commas for multiline arrays, objects, imports, exports, and function params
140
- - Blank lines between most statements
141
- - Import ordering with grouped and alphabetized imports
142
- - `no-var`, `prefer-const`, and a broad set of core correctness rules
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
143
162
  - Promise executor parameters named `resolve` and `reject`
144
163
 
145
- The Vue config also enforces `@/` imports inside `src/` through the bundled `no-relative-import-paths` rule and provides an autofix for matching relative imports.
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`
146
170
 
147
171
  ## Package Contents
148
172
 
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-object': 'error',
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@planfredapp/eslint-config",
3
- "version": "1.2.15",
3
+ "version": "1.3.0",
4
4
  "description": "Shared ESLint 10 flat configurations for Planfred projects",
5
5
  "keywords": [
6
6
  "eslint",
@@ -44,20 +44,20 @@
44
44
  "dependencies": {
45
45
  "@eslint/js": "10.0.1",
46
46
  "@stylistic/eslint-plugin": "5.10.0",
47
- "@vitest/eslint-plugin": "1.6.27",
47
+ "@vitest/eslint-plugin": "1.6.28",
48
48
  "eslint-plugin-cypress": "7.0.2",
49
49
  "eslint-plugin-import-x": "4.17.1",
50
- "eslint-plugin-n": "18.3.0",
50
+ "eslint-plugin-n": "18.5.0",
51
51
  "eslint-plugin-no-only-tests": "3.4.0",
52
- "eslint-plugin-vue": "10.11.0",
53
- "globals": "17.12.0",
54
- "typescript-eslint": "8.70.0",
52
+ "eslint-plugin-vue": "10.11.1",
53
+ "globals": "17.13.0",
54
+ "typescript-eslint": "8.72.0",
55
55
  "vue-eslint-parser": "10.4.1"
56
56
  },
57
57
  "devDependencies": {
58
- "eslint": "10.11.0",
58
+ "eslint": "10.13.0",
59
59
  "typescript": "6.0.3",
60
- "vitest": "5.0.1"
60
+ "vitest": "5.0.5"
61
61
  },
62
62
  "peerDependencies": {
63
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,