@scayle/eslint-config-storefront 4.8.3-alpha.1 → 5.0.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/CHANGELOG.md +100 -0
- package/README.md +94 -43
- package/config/ignores.mjs +46 -0
- package/config/index.mjs +129 -0
- package/config/javascript.mjs +159 -0
- package/config/rules.mjs +220 -0
- package/config/test.mjs +36 -0
- package/config/typescript.mjs +92 -0
- package/config/unicorn.mjs +33 -0
- package/config/v3/storybook.mjs +10 -0
- package/config/v3/tailwind.mjs +30 -0
- package/config/v3/vue.mjs +153 -0
- package/config/v3/vueComposable.mjs +29 -0
- package/config/v3/vueI18n.mjs +52 -0
- package/config/v3.mjs +49 -0
- package/config/v3.test.mjs +30 -0
- package/index.mjs +3 -2
- package/package.json +34 -15
- package/storefront-nuxt.mjs +4 -0
- package/storefront-v3.mjs +4 -0
- package/config/flat/importX.mjs +0 -22
- package/config/flat/index.mjs +0 -155
- package/config/flat/promise.mjs +0 -28
- package/config/flat/sonarjs.mjs +0 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,105 @@
|
|
|
1
1
|
# @aboutyou/eslint-config-sfc
|
|
2
2
|
|
|
3
|
+
## 5.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- Rebuilds the shared ESLint config directly on first-class plugins (`@eslint/js`, `typescript-eslint`, `eslint-plugin-n`, `eslint-plugin-jsonc`, `eslint-plugin-jsdoc`, `eslint-plugin-unicorn`, `eslint-plugin-regexp`, `@e18e/eslint-plugin`, `@eslint-community/eslint-plugin-eslint-comments`, `@vitest/eslint-plugin`) instead of wrapping `@antfu/eslint-config`. This drops the transitive dependency on framework-specific plugins (Vue, React, Astro, and others) this package never used, and makes every enabled rule visible directly in `config/`.
|
|
8
|
+
|
|
9
|
+
## Breaking changes
|
|
10
|
+
- `eslintConfigStorefront({ isNuxt: true })` is replaced by a dedicated entry point: `import eslintConfigStorefrontNuxt from '@scayle/eslint-config-storefront/nuxt'`. `eslintConfigStorefront()` no longer accepts an `isNuxt` option. It always applies the framework-agnostic and JavaScript/TypeScript/JSDoc rule set.
|
|
11
|
+
- Rules keep each plugin's own published name instead of antfu's renamed aliases: `@typescript-eslint/*` (not `ts/*`), `vitest/*` (not `test/*` for Vitest-specific rules; `no-only-tests/*` is unchanged). Update any inline `eslint-disable` comment that references the old alias.
|
|
12
|
+
- `config/flat/` moved to `config/`. Flat config is the only supported mode, so the `flat/` segment was redundant. If your project imported anything from `@scayle/eslint-config-storefront/config/flat/*` directly, update the import path.
|
|
13
|
+
- `@typescript-eslint/consistent-type-imports` now allows `import('mod').Type` inline type annotations (`disallowTypeAnnotations: false`), matching common TypeScript usage the previous rule severity silently never reached under the old rule composition.
|
|
14
|
+
- The `eslint` peer dependency floor moves from `>=9.0.0` to `>=10.4.0`, matching what `eslint-plugin-unicorn@73` actually requires. An ESLint 9 project installed this package cleanly before but hit unmet peer warnings from the plugins themselves. Upgrade ESLint to 10.4 or later before upgrading this package.
|
|
15
|
+
|
|
16
|
+
## New rule sets
|
|
17
|
+
|
|
18
|
+
Three additions widen the default coverage. Each is on by default in both `eslintConfigStorefront()` and `eslintConfigStorefrontNuxt()`, and each can surface new findings in an existing project on upgrade:
|
|
19
|
+
|
|
20
|
+
- **`eslint-plugin-unicorn`**: a curated subset of modernization rules (not the plugin's full `recommended` preset, which is hundreds of rules and largely stylistic). Covers things like preferring `node:`-prefixed core imports, `Array.isArray` over `instanceof Array`, and `Number.isNaN` over the global `isNaN`.
|
|
21
|
+
- **`eslint-plugin-regexp`**: the plugin's own `flat/recommended` preset. Flags unsafe or redundant regex patterns, including some that can cause catastrophic backtracking.
|
|
22
|
+
- **`@e18e/eslint-plugin`**: the [e18e](https://e18e.dev) community's `recommended` preset (modernization, module-replacement, and performance rules), with every rule downgraded to `warn`. The plugin is pre-1.0, and its rule set hasn't been reviewed against every consuming project yet, so findings surface without failing CI. Includes `ban-dependencies`, which flags known heavier packages with a lighter recommended alternative (for example `ora` in favor of `nanospinner`). Treat a `ban-dependencies` finding as a suggestion to evaluate, not a required change: swapping a dependency is a real decision with its own testing burden, not a lint fix.
|
|
23
|
+
|
|
24
|
+
## Upgrading
|
|
25
|
+
1. Run `eslint .` after upgrading. Fix or explicitly suppress any new finding before merging.
|
|
26
|
+
2. If your project used `eslintConfigStorefront({ isNuxt: true })`, switch to the `/nuxt` entry point:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
// Before
|
|
30
|
+
import eslintConfigStorefront from '@scayle/eslint-config-storefront'
|
|
31
|
+
export default eslintConfigStorefront({ isNuxt: true })
|
|
32
|
+
|
|
33
|
+
// After
|
|
34
|
+
import eslintConfigStorefrontNuxt from '@scayle/eslint-config-storefront/nuxt'
|
|
35
|
+
export default eslintConfigStorefrontNuxt()
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
3. Search your project for any inline rule reference using an antfu alias (`ts/`, `test/` for Vitest rules) and update it to the plugin's real prefix (`@typescript-eslint/`, `vitest/`).
|
|
39
|
+
|
|
40
|
+
- Adds `@scayle/eslint-config-storefront/v3`, a third entry point for the Storefront Application V3 stack (Hono, Inertia.js, Vue 3, not Nuxt). It builds on the default config and adds Vue language wiring, Vue rules, accessibility rules, `vue-i18n` linting, `@scayle/vue-composable` rules, Storybook file conventions, Tailwind CSS class validation, and `vue/block-order` enforcement.
|
|
41
|
+
|
|
42
|
+
## Breaking changes
|
|
43
|
+
- The named exports `eslintConfigStorefront` and `eslintConfigStorefrontNuxt` are now `storefront` and `storefrontNuxt`. Neither name, nor the `./nuxt` entry point itself, shipped in a published release before this change, so this only affects code already on this pre-release. Default exports are unaffected:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
// Before
|
|
47
|
+
import { eslintConfigStorefront } from '@scayle/eslint-config-storefront'
|
|
48
|
+
|
|
49
|
+
// After
|
|
50
|
+
import { storefront } from '@scayle/eslint-config-storefront'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- `vue/block-order` is now enforced at error severity on `./v3`, with `template` before `script` before `style`. `eslint-plugin-vue`'s own `recommended` default only warns and defaults to script-first. Any `.vue` file with a script or style block ahead of its template now fails lint. Run `eslint --fix` to reorder them; the fix is purely mechanical and doesn't change behavior.
|
|
54
|
+
|
|
55
|
+
## New entry point
|
|
56
|
+
|
|
57
|
+
`@scayle/eslint-config-storefront/v3` takes required `tailwind.entryPoint` and `i18n.localeDir` options, since the underlying plugins can't validate Tailwind classes or i18n keys without a real path. Optional options cover a shop's own custom elements, dynamically-used i18n keys, and fallthrough-attribute exceptions:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// eslint.config.mjs
|
|
61
|
+
import storefrontV3 from '@scayle/eslint-config-storefront/v3'
|
|
62
|
+
|
|
63
|
+
export default storefrontV3({
|
|
64
|
+
tailwind: {
|
|
65
|
+
entryPoint: './src/client/index.css',
|
|
66
|
+
},
|
|
67
|
+
i18n: {
|
|
68
|
+
localeDir: './src/i18n/locales/*.json',
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Named `v3`, not `vue`, since a future non-Vue Storefront Application V3 stack would extend this same entry point rather than needing a separate one.
|
|
74
|
+
|
|
75
|
+
### Patch Changes
|
|
76
|
+
|
|
77
|
+
- Added dependency `@e18e/eslint-plugin@^0.8.0`
|
|
78
|
+
- Added dependency `@eslint-community/eslint-plugin-eslint-comments@^4.7.2`
|
|
79
|
+
- Added dependency `@eslint/js@^10.0.0`
|
|
80
|
+
- Added dependency `@intlify/eslint-plugin-vue-i18n@^4.5.1`
|
|
81
|
+
- Added dependency `@scayle/eslint-plugin-vue-composable@workspace:*`
|
|
82
|
+
- Added dependency `@vitest/eslint-plugin@^1.6.20`
|
|
83
|
+
- Added dependency `eslint-plugin-better-tailwindcss@^4.7.0`
|
|
84
|
+
- Added dependency `eslint-plugin-jsdoc@^64.2.1`
|
|
85
|
+
- Added dependency `eslint-plugin-jsonc@^3.4.1`
|
|
86
|
+
- Added dependency `eslint-plugin-n@^18.3.0`
|
|
87
|
+
- Added dependency `eslint-plugin-no-only-tests@^3.4.0`
|
|
88
|
+
- Added dependency `eslint-plugin-regexp@^3.2.0`
|
|
89
|
+
- Added dependency `eslint-plugin-storybook@^10.5.8`
|
|
90
|
+
- Added dependency `eslint-plugin-unicorn@^73.0.0`
|
|
91
|
+
- Added dependency `eslint-plugin-vue@^10.10.0`
|
|
92
|
+
- Added dependency `eslint-plugin-vuejs-accessibility@^2.6.0`
|
|
93
|
+
- Added dependency `globals@^17.7.0`
|
|
94
|
+
- Added dependency `vue-eslint-parser@^10.4.1`
|
|
95
|
+
- Removed dependency `@antfu/eslint-config@^9.0.0`
|
|
96
|
+
- Removed dependency `@eslint/eslintrc@^3.3.5`
|
|
97
|
+
- Removed dependency `local-pkg@^1.2.1`
|
|
98
|
+
- Updated dependency `eslint-config-flat-gitignore@^2.2.0` to `eslint-config-flat-gitignore@^2.3.0`
|
|
99
|
+
- Updated dependency `eslint-plugin-import-x@^4.16.2` to `eslint-plugin-import-x@^4.17.1`
|
|
100
|
+
- Updated dependency `eslint-plugin-sonarjs@^4.0.3` to `eslint-plugin-sonarjs@^4.2.0`
|
|
101
|
+
- Updated dependency `typescript-eslint@8.67.0` to `typescript-eslint@^8.67.0`
|
|
102
|
+
|
|
3
103
|
## 4.8.3-alpha.1
|
|
4
104
|
|
|
5
105
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
A [shared `eslint` config](https://eslint.org/docs/latest/extend/shareable-configs#creating-a-shareable-config) for SCAYLE Storefront projects and packages.
|
|
4
4
|
Provides SCAYLE-specific `eslint` configuration for Frontend and Node.js projects using TypeScript.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Flat config only ([ESLint 10.4+](https://eslint.org/docs/latest/use/configure/configuration-files)). Built directly on first-class plugins (`@eslint/js`, `typescript-eslint`, `eslint-plugin-n`, `eslint-plugin-jsonc`, `eslint-plugin-jsdoc`, `eslint-plugin-unicorn`, `eslint-plugin-regexp`, `@e18e/eslint-plugin`, and others) with no shared-config aggregator dependency.
|
|
7
7
|
|
|
8
8
|
Should you require support for `eslint@8`, please use `@scayle/eslint-config-storefront@3`.
|
|
9
9
|
|
|
10
|
-
- Partially based on [@antfu/eslint-config](https://github.com/antfu/eslint-config)
|
|
11
10
|
- [Official ESLint Documentation](https://eslint.org/docs/latest/)
|
|
12
11
|
|
|
13
12
|
---
|
|
@@ -24,11 +23,54 @@ And create a `eslint.config.mjs` in your project root:
|
|
|
24
23
|
|
|
25
24
|
```js
|
|
26
25
|
// eslint.config.mjs
|
|
27
|
-
import
|
|
26
|
+
import storefront from '@scayle/eslint-config-storefront'
|
|
28
27
|
|
|
29
|
-
export default
|
|
28
|
+
export default storefront()
|
|
30
29
|
```
|
|
31
30
|
|
|
31
|
+
### Nuxt projects
|
|
32
|
+
|
|
33
|
+
Nuxt projects already get JavaScript, TypeScript, JSDoc, and import rules from
|
|
34
|
+
[`@nuxt/eslint`](https://eslint.nuxt.com/). Use the `/nuxt` entry point instead, which
|
|
35
|
+
only adds the framework-agnostic rules (comments hygiene, Node.js, JSON/JSONC, test-file
|
|
36
|
+
conventions, SonarJS, Promise usage, modernization, and regex safety):
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
// eslint.config.mjs
|
|
40
|
+
import storefrontNuxt from '@scayle/eslint-config-storefront/nuxt'
|
|
41
|
+
import withNuxt from './.nuxt/eslint.config.mjs'
|
|
42
|
+
|
|
43
|
+
export default withNuxt(storefrontNuxt())
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Storefront Application V3 projects
|
|
47
|
+
|
|
48
|
+
The Storefront Application V3 stack (Hono + Inertia.js + Vue 3, not Nuxt) should use the
|
|
49
|
+
`/v3` entry point. It builds on the default config and adds Vue language wiring, Vue rules,
|
|
50
|
+
accessibility rules, `vue-i18n` linting, `@scayle/vue-composable` rules, Storybook file
|
|
51
|
+
conventions, and Tailwind CSS class validation:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
// eslint.config.mjs
|
|
55
|
+
import storefrontV3 from '@scayle/eslint-config-storefront/v3'
|
|
56
|
+
|
|
57
|
+
export default storefrontV3({
|
|
58
|
+
tailwind: {
|
|
59
|
+
entryPoint: './src/client/index.css',
|
|
60
|
+
},
|
|
61
|
+
i18n: {
|
|
62
|
+
localeDir: './src/i18n/locales/*.json',
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`tailwind.entryPoint` and `i18n.localeDir` are required, the underlying plugins can't
|
|
68
|
+
validate Tailwind classes or i18n keys without a real path. Optional options:
|
|
69
|
+
|
|
70
|
+
- `i18n.unusedKeyIgnores`: regex-string patterns for translation keys used dynamically in code
|
|
71
|
+
- `vue.undefComponentIgnores`: custom element (web component) tag names to exempt from `vue/no-undef-components`
|
|
72
|
+
- `vueComposable.fallthroughAttrsIgnores`: path fragments to exempt from `require-explicit-fallthrough-attrs` (e.g. router-mounted page/layout roots that never receive fallthrough attributes)
|
|
73
|
+
|
|
32
74
|
### Add script for package.json
|
|
33
75
|
|
|
34
76
|
For example:
|
|
@@ -77,66 +119,75 @@ Add the following settings to your `.vscode/settings.json`:
|
|
|
77
119
|
|
|
78
120
|
## Customization
|
|
79
121
|
|
|
80
|
-
###
|
|
81
|
-
|
|
82
|
-
#### Default config / `@scayle/eslint-config-storefront`
|
|
83
|
-
|
|
84
|
-
Normally you only need to import the antfu preset:
|
|
122
|
+
### Default config / `@scayle/eslint-config-storefront`
|
|
85
123
|
|
|
86
124
|
```js
|
|
87
125
|
// eslint.config.mjs
|
|
88
|
-
import
|
|
126
|
+
import storefront from '@scayle/eslint-config-storefront'
|
|
89
127
|
|
|
90
|
-
export default
|
|
128
|
+
export default storefront({
|
|
129
|
+
typescript: {
|
|
130
|
+
// Enables type-aware rules for the given tsconfig
|
|
131
|
+
tsconfigPath: 'path/to/tsconfig.json',
|
|
132
|
+
},
|
|
133
|
+
})
|
|
91
134
|
```
|
|
92
135
|
|
|
93
|
-
###
|
|
136
|
+
### Nuxt config / `@scayle/eslint-config-storefront/nuxt`
|
|
94
137
|
|
|
95
138
|
```js
|
|
96
139
|
// eslint.config.mjs
|
|
97
|
-
import
|
|
140
|
+
import storefrontNuxt from '@scayle/eslint-config-storefront/nuxt'
|
|
98
141
|
|
|
99
|
-
export default
|
|
100
|
-
|
|
101
|
-
// that are provided by the `@nuxt/eslint` package
|
|
102
|
-
isNuxt: true, // Default via auto-detection of package `@nuxt/eslint`
|
|
142
|
+
export default storefrontNuxt()
|
|
143
|
+
```
|
|
103
144
|
|
|
104
|
-
|
|
105
|
-
isTailwind: true, // Default via auto-detection of package `eslint-plugin-tailwind`
|
|
145
|
+
### Storefront Application V3 config / `@scayle/eslint-config-storefront/v3`
|
|
106
146
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
```
|
|
147
|
+
See [Storefront Application V3 projects](#storefront-application-v3-projects) above for the full option list.
|
|
148
|
+
|
|
149
|
+
All three entry points return a [`FlatConfigComposer`](https://github.com/antfu/eslint-flat-config-utils),
|
|
150
|
+
so you can chain `.append(...)`, `.prepend(...)`, `.override(...)`, or `.renamePlugins(...)` to layer
|
|
151
|
+
project-specific rules on top.
|
|
152
|
+
|
|
153
|
+
### Plugin names
|
|
115
154
|
|
|
116
|
-
|
|
155
|
+
Rules use each plugin's own published name (`@typescript-eslint/*`, `import-x/*`, `jsonc/*`,
|
|
156
|
+
`jsdoc/*`, `node/*`, `promise/*`, `sonarjs/*`, `unicorn/*`, `regexp/*`, `e18e/*`, `vitest/*`,
|
|
157
|
+
`eslint-comments/*`). There's no alias renaming. When you override or disable a rule inline,
|
|
158
|
+
use that plugin's real prefix:
|
|
117
159
|
|
|
118
|
-
|
|
160
|
+
```js
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
162
|
+
type Foo = { bar: 2 }
|
|
163
|
+
```
|
|
119
164
|
|
|
120
|
-
|
|
121
|
-
| ---------- | ---------------------- | ------------------------------------------------------------------------------------------ |
|
|
122
|
-
| `import/*` | `import-x/*` | [eslint-plugin-import-x](https://github.com/un-es/eslint-plugin-import-x) |
|
|
123
|
-
| `node/*` | `n/*` | [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n) |
|
|
124
|
-
| `yaml/*` | `yml/*` | [eslint-plugin-yml](https://github.com/ota-meshi/eslint-plugin-yml) |
|
|
125
|
-
| `ts/*` | `@typescript-eslint/*` | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint) |
|
|
126
|
-
| `test/*` | `vitest/*` | [eslint-plugin-vitest](https://github.com/veritem/eslint-plugin-vitest) |
|
|
127
|
-
| `test/*` | `no-only-tests/*` | [eslint-plugin-no-only-tests](https://github.com/levibuzolic/eslint-plugin-no-only-tests) |
|
|
165
|
+
### `e18e/*` rules ship as warnings
|
|
128
166
|
|
|
129
|
-
|
|
167
|
+
The [e18e](https://e18e.dev) community's rule set (modernization, module-replacement, and
|
|
168
|
+
performance rules) is enabled by default, but every `e18e/*` rule ships at `warn`, not `error`.
|
|
169
|
+
The plugin is still pre-1.0, and its rule set hasn't been reviewed against every consuming
|
|
170
|
+
project. A warning won't fail your build.
|
|
130
171
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
172
|
+
One rule worth knowing about specifically: `e18e/ban-dependencies` flags a dependency in your
|
|
173
|
+
project that has a lighter recommended alternative (for example `ora` in favor of
|
|
174
|
+
`nanospinner`). Treat that finding as something to evaluate, not something to fix immediately.
|
|
175
|
+
Swapping a dependency is a real decision with its own testing cost, not a lint fix. If you've
|
|
176
|
+
decided to keep a flagged dependency, allowlist it explicitly rather than turning the rule off:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
export default storefront().append({
|
|
180
|
+
rules: {
|
|
181
|
+
'e18e/ban-dependencies': ['warn', { allowed: ['ora'] }],
|
|
182
|
+
},
|
|
183
|
+
})
|
|
135
184
|
```
|
|
136
185
|
|
|
137
186
|
## View what rules are enabled
|
|
138
187
|
|
|
139
|
-
[
|
|
188
|
+
[@eslint/config-inspector](https://github.com/eslint/config-inspector) is a visual tool maintained
|
|
189
|
+
by the ESLint core team to help you view what rules are enabled in your project and which files
|
|
190
|
+
they apply to.
|
|
140
191
|
|
|
141
192
|
Go into your project root that contains eslint.config.js and run:
|
|
142
193
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Build artifacts, lockfiles, and tooling caches that no project should lint.
|
|
2
|
+
export const GLOB_EXCLUDE = [
|
|
3
|
+
'**/node_modules',
|
|
4
|
+
'**/dist',
|
|
5
|
+
'**/package-lock.json',
|
|
6
|
+
'**/yarn.lock',
|
|
7
|
+
'**/pnpm-lock.yaml',
|
|
8
|
+
'**/bun.lockb',
|
|
9
|
+
'**/output',
|
|
10
|
+
'**/coverage',
|
|
11
|
+
'**/playwright-report',
|
|
12
|
+
'**/test-results',
|
|
13
|
+
'**/temp',
|
|
14
|
+
'**/.temp',
|
|
15
|
+
'**/tmp',
|
|
16
|
+
'**/.tmp',
|
|
17
|
+
'**/.history',
|
|
18
|
+
'**/.vitepress/cache',
|
|
19
|
+
'**/.nuxt',
|
|
20
|
+
'**/.next',
|
|
21
|
+
'**/.svelte-kit',
|
|
22
|
+
'**/.vercel',
|
|
23
|
+
'**/.changeset',
|
|
24
|
+
'**/.idea',
|
|
25
|
+
'**/.cache',
|
|
26
|
+
'**/.output',
|
|
27
|
+
'**/.vite-inspect',
|
|
28
|
+
'**/.yarn',
|
|
29
|
+
'**/CHANGELOG*.md',
|
|
30
|
+
'**/LICENSE*',
|
|
31
|
+
'**/*.min.*',
|
|
32
|
+
'**/__snapshots__',
|
|
33
|
+
'**/vite.config.*.timestamp-*',
|
|
34
|
+
'**/auto-import?(s).d.ts',
|
|
35
|
+
'**/components.d.ts',
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
/** @returns {import('eslint').Linter.Config[]} Flat config entries excluding build artifacts and tooling caches from linting. */
|
|
39
|
+
export function ignoresConfig() {
|
|
40
|
+
return [
|
|
41
|
+
{
|
|
42
|
+
name: 'storefront/ignores',
|
|
43
|
+
ignores: GLOB_EXCLUDE,
|
|
44
|
+
},
|
|
45
|
+
]
|
|
46
|
+
}
|
package/config/index.mjs
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { FlatConfigComposer } from 'eslint-flat-config-utils'
|
|
2
|
+
import gitignore from 'eslint-config-flat-gitignore'
|
|
3
|
+
import {
|
|
4
|
+
commentsConfig,
|
|
5
|
+
nodeConfig,
|
|
6
|
+
jsoncConfig,
|
|
7
|
+
sonarjsConfig,
|
|
8
|
+
promiseConfig,
|
|
9
|
+
importXConfig,
|
|
10
|
+
jsdocConfig,
|
|
11
|
+
regexpConfig,
|
|
12
|
+
e18eConfig,
|
|
13
|
+
} from './rules.mjs'
|
|
14
|
+
import { testConfig, GLOB_TESTS } from './test.mjs'
|
|
15
|
+
import { ignoresConfig } from './ignores.mjs'
|
|
16
|
+
import { javascriptConfig } from './javascript.mjs'
|
|
17
|
+
import { typescriptConfig } from './typescript.mjs'
|
|
18
|
+
import { unicornConfig } from './unicorn.mjs'
|
|
19
|
+
|
|
20
|
+
/** @type {import('eslint').Linter.RuleEntry} */
|
|
21
|
+
const CURLY_RULE = ['error', 'all']
|
|
22
|
+
|
|
23
|
+
/** @type {import('eslint').Linter.RulesRecord} */
|
|
24
|
+
const GLOBAL_RULES = {
|
|
25
|
+
curly: CURLY_RULE,
|
|
26
|
+
'node/prefer-global/process': 'off',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** @type {import('eslint').Linter.RulesRecord} */
|
|
30
|
+
const TEST_RULES = {
|
|
31
|
+
'no-console': 'off',
|
|
32
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
33
|
+
'promise/avoid-new': 'off',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const IGNORE_PATTERNS = ['**/fixtures/**/*', '**/*.jsonc']
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @typedef {object} EslintConfigStorefrontOptions
|
|
40
|
+
* @property {object} [typescript] Options forwarded to `typescriptConfig`.
|
|
41
|
+
* @property {string} [typescript.tsconfigPath] Enables type-aware TypeScript rules when set.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
// Rules shared by every project regardless of framework: comments hygiene, Node.js,
|
|
45
|
+
// JSON/JSONC, test-file conventions, SonarJS, Promise usage, modernization (unicorn,
|
|
46
|
+
// e18e), and regex safety.
|
|
47
|
+
function baseConfigs() {
|
|
48
|
+
return [
|
|
49
|
+
...commentsConfig(),
|
|
50
|
+
...nodeConfig(),
|
|
51
|
+
...jsoncConfig(),
|
|
52
|
+
...testConfig(),
|
|
53
|
+
...sonarjsConfig(),
|
|
54
|
+
...promiseConfig(),
|
|
55
|
+
...unicornConfig(),
|
|
56
|
+
...e18eConfig(),
|
|
57
|
+
...regexpConfig(),
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Global and test-file overrides. Flat config is last-match-wins, so these must be
|
|
62
|
+
// appended after typescriptConfig() (and, on the base entry point, javascriptConfig()
|
|
63
|
+
// and jsdocConfig()) on both entry points, not folded into baseConfigs(): otherwise a
|
|
64
|
+
// rule these set (e.g. @typescript-eslint/no-explicit-any: 'off' for test files) gets
|
|
65
|
+
// re-enabled by a later config with the same rule key for the same files.
|
|
66
|
+
function overrideConfigs() {
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
rules: GLOBAL_RULES,
|
|
70
|
+
ignores: [IGNORE_PATTERNS[0]],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
files: GLOB_TESTS,
|
|
74
|
+
rules: TEST_RULES,
|
|
75
|
+
},
|
|
76
|
+
{ ignores: [IGNORE_PATTERNS[1]] },
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Builds the SCAYLE Storefront ESLint flat config for a framework-agnostic or
|
|
82
|
+
* plain TypeScript project. Nuxt projects should use
|
|
83
|
+
* `@scayle/eslint-config-storefront/nuxt` instead, since `@nuxt/eslint` already
|
|
84
|
+
* covers JavaScript, TypeScript, JSDoc, and import rules.
|
|
85
|
+
*
|
|
86
|
+
* @param {EslintConfigStorefrontOptions} [config]
|
|
87
|
+
* @returns {FlatConfigComposer<import('eslint').Linter.Config, never>} Returns a FlatConfigComposer object to be consumed in projects eslint.config.mjs files
|
|
88
|
+
*/
|
|
89
|
+
export const storefront = function (config = {}) {
|
|
90
|
+
/** @type {FlatConfigComposer<import('eslint').Linter.Config, never>} */
|
|
91
|
+
const flatConfigComposer = new FlatConfigComposer()
|
|
92
|
+
|
|
93
|
+
const configs = [
|
|
94
|
+
...baseConfigs(),
|
|
95
|
+
gitignore({ strict: false }),
|
|
96
|
+
...ignoresConfig(),
|
|
97
|
+
...importXConfig(),
|
|
98
|
+
...javascriptConfig(),
|
|
99
|
+
...typescriptConfig(config.typescript),
|
|
100
|
+
...jsdocConfig(),
|
|
101
|
+
// Set tsconfigRootDir for all TypeScript files to support monorepo structure
|
|
102
|
+
// This ensures ESLint uses the correct tsconfig.json when multiple exist
|
|
103
|
+
{
|
|
104
|
+
files: ['**/*.mjs', '**/*.cjs', '**/*.ts', '**/*.tsx'],
|
|
105
|
+
languageOptions: {
|
|
106
|
+
parserOptions: {
|
|
107
|
+
tsconfigRootDir: process.cwd(),
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
...overrideConfigs(),
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
return flatConfigComposer.append(...configs)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Builds the SCAYLE Storefront ESLint flat config for a Nuxt project. Omits
|
|
119
|
+
* JavaScript, TypeScript, JSDoc, ignores, and import rules, since `@nuxt/eslint`
|
|
120
|
+
* already provides those for a Nuxt project.
|
|
121
|
+
*
|
|
122
|
+
* @returns {FlatConfigComposer<import('eslint').Linter.Config, never>} Returns a FlatConfigComposer object to be consumed in projects eslint.config.mjs files
|
|
123
|
+
*/
|
|
124
|
+
export const storefrontNuxt = function () {
|
|
125
|
+
/** @type {FlatConfigComposer<import('eslint').Linter.Config, never>} */
|
|
126
|
+
const flatConfigComposer = new FlatConfigComposer()
|
|
127
|
+
|
|
128
|
+
return flatConfigComposer.append(...baseConfigs(), ...overrideConfigs())
|
|
129
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
|
|
4
|
+
// Core JavaScript correctness rules, plus a handful of Storefront-specific overrides
|
|
5
|
+
// on top of `@eslint/js`'s `recommended` preset.
|
|
6
|
+
/** @returns {import('eslint').Linter.Config[]} Flat config entries for core JavaScript correctness rules. */
|
|
7
|
+
export function javascriptConfig() {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
name: 'storefront/javascript/setup',
|
|
11
|
+
languageOptions: {
|
|
12
|
+
ecmaVersion: 'latest',
|
|
13
|
+
sourceType: 'module',
|
|
14
|
+
globals: {
|
|
15
|
+
...globals.browser,
|
|
16
|
+
...globals.es2021,
|
|
17
|
+
...globals.node,
|
|
18
|
+
},
|
|
19
|
+
parserOptions: {
|
|
20
|
+
ecmaFeatures: { jsx: true },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'storefront/javascript/rules',
|
|
26
|
+
rules: {
|
|
27
|
+
...js.configs.recommended.rules,
|
|
28
|
+
'accessor-pairs': [
|
|
29
|
+
'error',
|
|
30
|
+
{ enforceForClassMembers: true, setWithoutGet: true },
|
|
31
|
+
],
|
|
32
|
+
'array-callback-return': 'error',
|
|
33
|
+
'block-scoped-var': 'error',
|
|
34
|
+
'default-case-last': 'error',
|
|
35
|
+
'dot-notation': ['error', { allowKeywords: true }],
|
|
36
|
+
eqeqeq: ['error', 'smart'],
|
|
37
|
+
'new-cap': [
|
|
38
|
+
'error',
|
|
39
|
+
{ capIsNew: false, newIsCap: true, properties: true },
|
|
40
|
+
],
|
|
41
|
+
'no-alert': 'error',
|
|
42
|
+
'no-caller': 'error',
|
|
43
|
+
'no-eval': 'error',
|
|
44
|
+
'no-extend-native': 'error',
|
|
45
|
+
'no-extra-bind': 'error',
|
|
46
|
+
'no-implied-eval': 'error',
|
|
47
|
+
'no-iterator': 'error',
|
|
48
|
+
'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
|
|
49
|
+
'no-lone-blocks': 'error',
|
|
50
|
+
'no-multi-str': 'error',
|
|
51
|
+
'no-new': 'error',
|
|
52
|
+
'no-new-func': 'error',
|
|
53
|
+
'no-new-wrappers': 'error',
|
|
54
|
+
'no-octal-escape': 'error',
|
|
55
|
+
'no-proto': 'error',
|
|
56
|
+
'no-restricted-globals': [
|
|
57
|
+
'error',
|
|
58
|
+
{ name: 'global', message: 'Use `globalThis` instead.' },
|
|
59
|
+
{ name: 'self', message: 'Use `globalThis` instead.' },
|
|
60
|
+
],
|
|
61
|
+
'no-restricted-properties': [
|
|
62
|
+
'error',
|
|
63
|
+
{
|
|
64
|
+
property: '__proto__',
|
|
65
|
+
message:
|
|
66
|
+
'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
property: '__defineGetter__',
|
|
70
|
+
message: 'Use `Object.defineProperty` instead.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
property: '__defineSetter__',
|
|
74
|
+
message: 'Use `Object.defineProperty` instead.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
property: '__lookupGetter__',
|
|
78
|
+
message: 'Use `Object.getOwnPropertyDescriptor` instead.',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
property: '__lookupSetter__',
|
|
82
|
+
message: 'Use `Object.getOwnPropertyDescriptor` instead.',
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
'no-self-compare': 'error',
|
|
86
|
+
'no-sequences': 'error',
|
|
87
|
+
'no-template-curly-in-string': 'error',
|
|
88
|
+
'no-throw-literal': 'error',
|
|
89
|
+
'no-undef-init': 'error',
|
|
90
|
+
'no-unmodified-loop-condition': 'error',
|
|
91
|
+
'no-unneeded-ternary': ['error', { defaultAssignment: false }],
|
|
92
|
+
'no-unreachable-loop': 'error',
|
|
93
|
+
'no-unused-expressions': [
|
|
94
|
+
'error',
|
|
95
|
+
{
|
|
96
|
+
allowShortCircuit: true,
|
|
97
|
+
allowTernary: true,
|
|
98
|
+
allowTaggedTemplates: true,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
'no-unused-vars': [
|
|
102
|
+
'error',
|
|
103
|
+
{
|
|
104
|
+
args: 'all',
|
|
105
|
+
argsIgnorePattern: '^_',
|
|
106
|
+
caughtErrors: 'all',
|
|
107
|
+
caughtErrorsIgnorePattern: '^_',
|
|
108
|
+
destructuredArrayIgnorePattern: '^_',
|
|
109
|
+
varsIgnorePattern: '^_',
|
|
110
|
+
ignoreRestSiblings: true,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
'no-use-before-define': [
|
|
114
|
+
'error',
|
|
115
|
+
{ functions: false, classes: false, variables: true },
|
|
116
|
+
],
|
|
117
|
+
'no-useless-call': 'error',
|
|
118
|
+
'no-useless-computed-key': 'error',
|
|
119
|
+
// Off: a subclass constructor that only forwards to `super(...)` is
|
|
120
|
+
// still meaningful documentation of the accepted argument types at
|
|
121
|
+
// an extension point (e.g. a mapper/service subclass), even when it
|
|
122
|
+
// matches the base class's signature exactly.
|
|
123
|
+
'no-useless-constructor': 'off',
|
|
124
|
+
'no-useless-rename': 'error',
|
|
125
|
+
'no-useless-return': 'error',
|
|
126
|
+
'no-var': 'error',
|
|
127
|
+
'object-shorthand': [
|
|
128
|
+
'error',
|
|
129
|
+
'always',
|
|
130
|
+
{ avoidQuotes: true, ignoreConstructors: false },
|
|
131
|
+
],
|
|
132
|
+
'one-var': ['error', { initialized: 'never' }],
|
|
133
|
+
'prefer-arrow-callback': [
|
|
134
|
+
'error',
|
|
135
|
+
{ allowNamedFunctions: false, allowUnboundThis: true },
|
|
136
|
+
],
|
|
137
|
+
'prefer-const': [
|
|
138
|
+
'error',
|
|
139
|
+
{ destructuring: 'all', ignoreReadBeforeAssign: true },
|
|
140
|
+
],
|
|
141
|
+
'prefer-exponentiation-operator': 'error',
|
|
142
|
+
'prefer-promise-reject-errors': 'error',
|
|
143
|
+
'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
|
|
144
|
+
'prefer-rest-params': 'error',
|
|
145
|
+
'prefer-spread': 'error',
|
|
146
|
+
'prefer-template': 'error',
|
|
147
|
+
'symbol-description': 'error',
|
|
148
|
+
'unicode-bom': ['error', 'never'],
|
|
149
|
+
'use-isnan': [
|
|
150
|
+
'error',
|
|
151
|
+
{ enforceForIndexOf: true, enforceForSwitchCase: true },
|
|
152
|
+
],
|
|
153
|
+
'valid-typeof': ['error', { requireStringLiterals: true }],
|
|
154
|
+
'vars-on-top': 'error',
|
|
155
|
+
yoda: ['error', 'never'],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
]
|
|
159
|
+
}
|