Skip to content

Commit 7254a39

Browse files
feat: add ESLint 9 support and update documentation/configs (#114)
* chore: increase version number * fix: mark eslint 8 as legacy * feat: add eslint 9 support * fix: update 'readme.md' and 'recommended.ts' config * fix: add `babelParser` to ESLint 8 recommended-legacy config
1 parent 21b3e9f commit 7254a39

File tree

9 files changed

+4102
-3775
lines changed

9 files changed

+4102
-3775
lines changed

README.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,27 @@ $ npm install --save-dev @salesforce/eslint-plugin-lwc-mobile
1818

1919
## Configuration
2020

21-
Here's an example snippet of a `.eslintrc.json` configuration file, that will configure the `eslint-plugin-lwc-mobile` plugin. Extending the `plugin:@salesforce/lwc-mobile/recommended` ESLint configuration will enable static analysis on all `.js` files used in your Lightning web components.
21+
### ESLint >= 9
22+
23+
The default configurations are now in the flat config format supported by ESLint 9 and beyond. To include `recommendedConfigs ` in your flat config, spread it into your configuration array. Note that `recommendedConfigs` is a collection of preset configs and must be expanded accordingly.:
24+
25+
```javascript
26+
// eslint.config.mjs
27+
import js from '@eslint/js';
28+
import lwcMobilePlugin from "@salesforce/eslint-plugin-lwc-mobile";
29+
30+
export default [
31+
{ plugins: { "@salesforce/lwc-mobile": lwcMobilePlugin } },
32+
js.configs.recommended,
33+
...lwcMobilePlugin.recommendedConfigs,
34+
];
35+
```
36+
37+
### ESLint < 9
38+
Configurations for legacy ESLint have moved to `-legacy` extensions. Here's an example snippet of a `.eslintrc.json` configuration file, that will configure the `eslint-plugin-lwc-mobile` plugin. Extending the `plugin:@salesforce/lwc-mobile/recommended-legacy` ESLint configuration will enable static analysis on all `.js` files used in your Lightning web components.
2239

2340
```json
2441
{
25-
"extends": ["eslint:recommended", "plugin:@salesforce/lwc-mobile/recommended"]
42+
"extends": ["eslint:recommended", "plugin:@salesforce/lwc-mobile/recommended-legacy"]
2643
}
2744
```

package-lock.json

Lines changed: 3942 additions & 3726 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@salesforce/eslint-plugin-lwc-mobile",
3-
"version": "0.0.1",
3+
"version": "1.0.0",
44
"description": "ESLint plugin for LWC mobility",
55
"contributors": [
66
{
@@ -31,7 +31,7 @@
3131
"url": "https://github.com/salesforce/eslint-plugin-lwc-mobile"
3232
},
3333
"scripts": {
34-
"clean": "npx rimraf dist reports",
34+
"clean": "npx rimraf dist reports tsconfig.tsbuildinfo",
3535
"build": "npm run clean && tsc",
3636
"format": "prettier --list-different \"**/*.{ts,js}\"",
3737
"format:fix": "prettier --write \"**/*.{ts,js,json}\"",
@@ -59,8 +59,11 @@
5959
"/dist"
6060
],
6161
"dependencies": {
62+
"@babel/core": "^7.27.4",
63+
"@babel/eslint-parser": "^7.27.5",
6264
"@graphql-eslint/eslint-plugin": "^3.20.1",
63-
"@typescript-eslint/utils": "^8.22.0"
65+
"@types/eslint": "^9.6.1",
66+
"typescript-eslint": "^8.17.0"
6467
},
6568
"devDependencies": {
6669
"@commitlint/cli": "^19.7.1",
@@ -71,13 +74,10 @@
7174
"@semantic-release/exec": "^6.0.3",
7275
"@semantic-release/git": "^10.0.1",
7376
"@semantic-release/npm": "^12.0.1",
74-
"@types/eslint": "^8.56.10",
7577
"@types/estree": "^1.0.6",
7678
"@types/jest": "^29.5.14",
77-
"@typescript-eslint/parser": "^8.27.0",
78-
"@typescript-eslint/rule-tester": "^8.27.0",
7979
"conventional-changelog-conventionalcommits": "^8.0.0",
80-
"eslint": "^8.57.0",
80+
"eslint": "^9.28.0",
8181
"eslint-plugin-eslint-plugin": "^6.4.0",
8282
"eslint-plugin-node": "^11.1.0",
8383
"husky": "^9.1.7",
@@ -91,8 +91,7 @@
9191
"semantic-release": "^24.2.3",
9292
"ts-jest": "^29.2.6",
9393
"ts-node": "^10.9.2",
94-
"typescript": "^5.8.2",
95-
"typescript-eslint": "^8.17.0"
94+
"typescript": "^5.8.2"
9695
},
9796
"peerDependencies": {
9897
"eslint": ">=7"
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
* SPDX-License-Identifier: MIT
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
66
*/
7-
import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint';
7+
import { Linter } from 'eslint';
88

99
export = {
1010
plugins: ['@salesforce/lwc-mobile', '@graphql-eslint']
11-
} satisfies ClassicConfig.Config;
11+
} satisfies Linter.BaseConfig;

src/configs/recommended-legacy.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2024, salesforce.com, inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: MIT
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6+
*/
7+
import { Linter } from 'eslint';
8+
import { APEX_IMPORT_RULE_ID } from '../rules/apex/apex-import.js';
9+
import { NO_MUTATION_SUPPORTED_RULE_ID } from '../rules/graphql/no-mutation-supported';
10+
import { NO_AGGREGATE_QUERY_SUPPORTED_RULE_ID } from '../rules/graphql/no-aggregate-query-supported';
11+
import { UNSUPPORTED_SCOPE_RULE_ID } from '../rules/graphql/unsupported-scope.js';
12+
import { NO_FISCAL_DATE_FILTER_SUPPORTED_RULE_ID } from '../rules/graphql/no-fiscal-date-filtering-supported.js';
13+
import { NO_SEMI_ANTI_JOIN_SUPPORTED_RULE_ID } from '../rules/graphql/no-semi-anti-join-supported';
14+
import { NO_MORE_THAN_1_PARENT_RECORD_RULE_ID } from '../rules/graphql/no-more-than-1-parent-record.js';
15+
import { NO_MORE_THAN_3_CHILD_ENTITIES_RULE_ID } from '../rules/graphql/no-more-than-3-child-entities.js';
16+
import { NO_MORE_THAN_3_ROOT_ENTITIES_RULE_ID } from '../rules/graphql/no-more-than-3-root-entities.js';
17+
import { NO_MORE_THAN_100_FIELDS_RULE_ID } from '../rules/graphql/no-more-than-100-fields.js';
18+
import { createScopedModuleRuleName } from '../util/rule-helpers.js';
19+
20+
export = {
21+
extends: ['./configs/base-legacy'],
22+
parser: '@babel/eslint-parser',
23+
parserOptions: {
24+
requireConfigFile: false,
25+
babelOptions: {
26+
parserOpts: {
27+
plugins: [['decorators', { decoratorsBeforeExport: false }]]
28+
}
29+
},
30+
ecmaVersion: 'latest',
31+
sourceType: 'module'
32+
},
33+
rules: {
34+
[createScopedModuleRuleName(APEX_IMPORT_RULE_ID)]: 'warn'
35+
},
36+
overrides: [
37+
{
38+
files: ['*.js'],
39+
processor: '@graphql-eslint/graphql'
40+
},
41+
{
42+
files: ['*.graphql'],
43+
parser: '@graphql-eslint/eslint-plugin',
44+
45+
parserOptions: {
46+
skipGraphQLConfig: true
47+
},
48+
rules: {
49+
[createScopedModuleRuleName(NO_AGGREGATE_QUERY_SUPPORTED_RULE_ID)]: 'warn',
50+
[createScopedModuleRuleName(NO_FISCAL_DATE_FILTER_SUPPORTED_RULE_ID)]: 'warn',
51+
[createScopedModuleRuleName(NO_MUTATION_SUPPORTED_RULE_ID)]: 'warn',
52+
[createScopedModuleRuleName(NO_SEMI_ANTI_JOIN_SUPPORTED_RULE_ID)]: 'warn',
53+
[createScopedModuleRuleName(NO_MORE_THAN_1_PARENT_RECORD_RULE_ID)]: 'warn',
54+
[createScopedModuleRuleName(NO_MORE_THAN_3_CHILD_ENTITIES_RULE_ID)]: 'warn',
55+
[createScopedModuleRuleName(NO_MORE_THAN_3_ROOT_ENTITIES_RULE_ID)]: 'warn',
56+
[createScopedModuleRuleName(NO_MORE_THAN_100_FIELDS_RULE_ID)]: 'warn',
57+
[createScopedModuleRuleName(UNSUPPORTED_SCOPE_RULE_ID)]: 'warn'
58+
}
59+
}
60+
]
61+
} satisfies Linter.BaseConfig;

src/configs/recommended.ts

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
* SPDX-License-Identifier: MIT
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
66
*/
7-
import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint';
7+
8+
import { Linter } from 'eslint';
9+
810
import { APEX_IMPORT_RULE_ID } from '../rules/apex/apex-import.js';
911
import { NO_MUTATION_SUPPORTED_RULE_ID } from '../rules/graphql/no-mutation-supported';
1012
import { NO_AGGREGATE_QUERY_SUPPORTED_RULE_ID } from '../rules/graphql/no-aggregate-query-supported';
@@ -16,35 +18,51 @@ import { NO_MORE_THAN_3_CHILD_ENTITIES_RULE_ID } from '../rules/graphql/no-more-
1618
import { NO_MORE_THAN_3_ROOT_ENTITIES_RULE_ID } from '../rules/graphql/no-more-than-3-root-entities.js';
1719
import { NO_MORE_THAN_100_FIELDS_RULE_ID } from '../rules/graphql/no-more-than-100-fields.js';
1820
import { createScopedModuleRuleName } from '../util/rule-helpers.js';
21+
import { parseForESLint as parseForESLintGraphQL } from '@graphql-eslint/eslint-plugin';
22+
import { parseForESLint as parseForESLintBabel, parse } from '@babel/eslint-parser';
23+
import { processors } from '@graphql-eslint/eslint-plugin';
1924

20-
export = {
21-
extends: ['./configs/base'],
22-
rules: {
23-
[createScopedModuleRuleName(APEX_IMPORT_RULE_ID)]: 'warn'
24-
},
25-
overrides: [
26-
{
27-
files: ['*.js'],
28-
processor: '@graphql-eslint/graphql'
25+
const configs: Linter.Config[] = [
26+
{
27+
files: ['*.js', '**/*.js'],
28+
languageOptions: {
29+
parser: { parseForESLint: parseForESLintBabel, parse },
30+
parserOptions: {
31+
requireConfigFile: false,
32+
babelOptions: {
33+
parserOpts: {
34+
plugins: [['decorators', { decoratorsBeforeExport: false }]]
35+
}
36+
},
37+
ecmaVersion: 'latest',
38+
sourceType: 'module'
39+
}
2940
},
30-
{
31-
files: ['*.graphql'],
32-
parser: '@graphql-eslint/eslint-plugin',
33-
41+
processor: processors.graphql,
42+
rules: {
43+
[createScopedModuleRuleName(APEX_IMPORT_RULE_ID)]: 'warn'
44+
}
45+
},
46+
{
47+
files: ['*.graphql', '**/*.graphql'],
48+
languageOptions: {
49+
parser: { parseForESLint: parseForESLintGraphQL },
3450
parserOptions: {
3551
skipGraphQLConfig: true
36-
},
37-
rules: {
38-
[createScopedModuleRuleName(NO_AGGREGATE_QUERY_SUPPORTED_RULE_ID)]: 'warn',
39-
[createScopedModuleRuleName(NO_FISCAL_DATE_FILTER_SUPPORTED_RULE_ID)]: 'warn',
40-
[createScopedModuleRuleName(NO_MUTATION_SUPPORTED_RULE_ID)]: 'warn',
41-
[createScopedModuleRuleName(NO_SEMI_ANTI_JOIN_SUPPORTED_RULE_ID)]: 'warn',
42-
[createScopedModuleRuleName(NO_MORE_THAN_1_PARENT_RECORD_RULE_ID)]: 'warn',
43-
[createScopedModuleRuleName(NO_MORE_THAN_3_CHILD_ENTITIES_RULE_ID)]: 'warn',
44-
[createScopedModuleRuleName(NO_MORE_THAN_3_ROOT_ENTITIES_RULE_ID)]: 'warn',
45-
[createScopedModuleRuleName(NO_MORE_THAN_100_FIELDS_RULE_ID)]: 'warn',
46-
[createScopedModuleRuleName(UNSUPPORTED_SCOPE_RULE_ID)]: 'warn'
4752
}
53+
},
54+
rules: {
55+
[createScopedModuleRuleName(NO_AGGREGATE_QUERY_SUPPORTED_RULE_ID)]: 'warn',
56+
[createScopedModuleRuleName(NO_FISCAL_DATE_FILTER_SUPPORTED_RULE_ID)]: 'warn',
57+
[createScopedModuleRuleName(NO_MUTATION_SUPPORTED_RULE_ID)]: 'warn',
58+
[createScopedModuleRuleName(NO_SEMI_ANTI_JOIN_SUPPORTED_RULE_ID)]: 'warn',
59+
[createScopedModuleRuleName(NO_MORE_THAN_1_PARENT_RECORD_RULE_ID)]: 'warn',
60+
[createScopedModuleRuleName(NO_MORE_THAN_3_CHILD_ENTITIES_RULE_ID)]: 'warn',
61+
[createScopedModuleRuleName(NO_MORE_THAN_3_ROOT_ENTITIES_RULE_ID)]: 'warn',
62+
[createScopedModuleRuleName(NO_MORE_THAN_100_FIELDS_RULE_ID)]: 'warn',
63+
[createScopedModuleRuleName(UNSUPPORTED_SCOPE_RULE_ID)]: 'warn'
4864
}
49-
]
50-
} satisfies ClassicConfig.Config;
65+
}
66+
];
67+
68+
export = configs;

src/index.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
66
*/
77

8-
import base from './configs/base.js';
9-
import recommended from './configs/recommended.js';
8+
import baseLegacy from './configs/base-legacy';
9+
import recommendedLegacy from './configs/recommended-legacy';
10+
import recommended from './configs/recommended';
1011
import { rule as apexImport, APEX_IMPORT_RULE_ID } from './rules/apex/apex-import.js';
1112
import {
1213
NO_AGGREGATE_QUERY_SUPPORTED_RULE_ID,
@@ -56,8 +57,8 @@ import { name, version } from '../package.json';
5657

5758
export = {
5859
configs: {
59-
base,
60-
recommended
60+
'base-legacy': baseLegacy,
61+
'recommended-legacy': recommendedLegacy
6162
},
6263
meta: {
6364
name,
@@ -74,5 +75,6 @@ export = {
7475
[NO_MORE_THAN_100_FIELDS_RULE_ID]: noMoreThan100Fields,
7576
[NO_SEMI_ANTI_JOIN_SUPPORTED_RULE_ID]: noSemiAntiJoinSupported,
7677
[UNSUPPORTED_SCOPE_RULE_ID]: unsupportedScope
77-
}
78+
},
79+
recommendedConfigs: recommended
7880
};

test/rules/apex/apex-import.spec.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,25 @@
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
66
*/
77

8-
import { RuleTester } from '@typescript-eslint/rule-tester';
9-
8+
import { RuleTester } from 'eslint';
9+
import { parseForESLint } from '@babel/eslint-parser';
1010
import { rule, APEX_IMPORT_RULE_ID } from '../../../src/rules/apex/apex-import';
1111

12-
const ruleTester = new RuleTester();
12+
const ruleTester = new RuleTester({
13+
languageOptions: {
14+
parser: { parseForESLint },
15+
parserOptions: {
16+
requireConfigFile: false,
17+
babelOptions: {
18+
parserOpts: {
19+
plugins: [['decorators', { decoratorsBeforeExport: false }]]
20+
}
21+
},
22+
ecmaVersion: 'latest',
23+
sourceType: 'module'
24+
}
25+
}
26+
});
1327

1428
ruleTester.run(APEX_IMPORT_RULE_ID, rule as any, {
1529
valid: [

test/shared.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
66
*/
77

8-
import { RuleTester } from '@typescript-eslint/rule-tester';
8+
import { RuleTester } from 'eslint';
99
import { parseForESLint } from '@graphql-eslint/eslint-plugin';
1010

1111
export const ruleTester = new RuleTester({

0 commit comments

Comments
 (0)