@open-xchange/linter-presets 0.1.4 → 0.1.5

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,3 @@
1
+ {
2
+ "typescript.tsdk": "node_modules/typescript/lib"
3
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.5] - 2024-07-23
4
+
5
+ - chore: bump dependencies
6
+
3
7
  ## [0.1.4] - 2024-07-15
4
8
 
5
9
  - added: [ESLint] option `language.nativeDecorators` to support native ES decorators in JS files
@@ -119,7 +119,7 @@ export default function base(options) {
119
119
  "object-shorthand": "error",
120
120
  "operator-assignment": "error",
121
121
  "prefer-arrow-callback": "error",
122
- "prefer-const": ["error", { ignoreReadBeforeAssign: true }],
122
+ "prefer-const": ["error", { destructuring: "all", ignoreReadBeforeAssign: true }],
123
123
  "prefer-numeric-literals": "error",
124
124
  "prefer-regex-literals": "error",
125
125
  "prefer-rest-params": "error",
@@ -63,9 +63,11 @@ export default function ts() {
63
63
  "@typescript-eslint/no-shadow": ["error", { ignoreOnInitialization: true }],
64
64
  "@typescript-eslint/no-unnecessary-template-expression": "error",
65
65
  "@typescript-eslint/no-unsafe-enum-comparison": "error",
66
+ "@typescript-eslint/no-unsafe-function-type": "error",
66
67
  "@typescript-eslint/no-unsafe-unary-minus": "error",
67
68
  "@typescript-eslint/no-unused-vars": ["error", NO_UNUSED_VARS_OPTIONS],
68
69
  "@typescript-eslint/no-useless-constructor": "error",
70
+ "@typescript-eslint/no-wrapper-object-types": "error",
69
71
  "@typescript-eslint/only-throw-error": "error",
70
72
  "@typescript-eslint/prefer-find": "error",
71
73
  "@typescript-eslint/prefer-literal-enum-member": "error",
@@ -1,14 +1,9 @@
1
1
  import type { TSESLint } from "@typescript-eslint/utils";
2
- import type { EnvBaseOptions, EnvRestrictedOptions } from "../shared/env-utils.js";
2
+ import type { EnvRestrictedOptions } from "../shared/env-utils.js";
3
3
  /**
4
4
  * Configuration options for the environment preset "env.browser".
5
5
  */
6
- export interface EnvBrowserOptions extends EnvBaseOptions {
7
- /**
8
- * All globals, imports, properties, and syntax constructs to be banned for
9
- * the files included by the environment.
10
- */
11
- restricted?: EnvRestrictedOptions;
6
+ export interface EnvBrowserOptions extends EnvRestrictedOptions {
12
7
  }
13
8
  /**
14
9
  * Creates configuration objects with global symbols and linter rules for for
@@ -1,6 +1,6 @@
1
1
  import JAVASCRIPT_GLOBALS from "globals";
2
2
  import CONFUSING_BROWSER_GLOBALS from "confusing-browser-globals";
3
- import { generateRestrictedRules } from "../shared/env-utils.js";
3
+ import { concatConfigs, createConfig, restrictedRules, customRules } from "../shared/env-utils.js";
4
4
  // constants ==================================================================
5
5
  /**
6
6
  * Global builtin symbols that are confusing or deprecated.
@@ -91,30 +91,19 @@ const RESTRICTED_GLOBALS = AMBIGUOUS_BROWSER_TYPES.map(name => {
91
91
  * An array of configuration objects to be added to the flat configuration.
92
92
  */
93
93
  export default function browser(options) {
94
- // configuration properties
95
- const { files, ignores = [], rules } = options;
94
+ return concatConfigs(
95
+ // register global symbols used in browser scripts
96
+ createConfig(options, {
97
+ languageOptions: {
98
+ globals: BROWSER_GLOBALS,
99
+ },
100
+ }),
96
101
  // generate the "no-restricted-?" rules according to passed configuration
97
- const restricted = generateRestrictedRules({
102
+ restrictedRules(options, {
98
103
  globals: RESTRICTED_GLOBALS,
99
104
  properties: RESTRICTED_PROPERTIES,
100
105
  syntax: RESTRICTED_SYNTAX,
101
- }, options?.restricted);
102
- return [
103
- // base configuration for the environment
104
- {
105
- files,
106
- ignores,
107
- // register global symbols used in browser scripts
108
- languageOptions: {
109
- globals: BROWSER_GLOBALS,
110
- },
111
- // configure rules
112
- rules: {
113
- ...restricted.rules,
114
- ...rules,
115
- },
116
- },
117
- // "no-restricted-?" rules overrides for specific files
118
- ...restricted.overrides,
119
- ];
106
+ }),
107
+ // custom rules
108
+ customRules(options));
120
109
  }
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import codeceptPlugin from "eslint-plugin-codeceptjs";
8
8
  import chaiExpectPlugin from "eslint-plugin-chai-expect";
9
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
9
10
  // functions ==================================================================
10
11
  /**
11
12
  * Creates configuration objects with global symbols and linter rules for E2E
@@ -22,40 +23,28 @@ import chaiExpectPlugin from "eslint-plugin-chai-expect";
22
23
  * An array of configuration objects to be added to the flat configuration.
23
24
  */
24
25
  export default function codecept(options) {
25
- // configuration properties
26
- const { files, ignores = [], rules } = options;
27
- return [
28
- {
29
- files,
30
- ignores,
31
- // register rule implementations of the plugins
32
- plugins: {
33
- codeceptjs: codeceptPlugin,
34
- },
35
- // register global symbols of CodeceptJS
36
- languageOptions: {
37
- globals: {
38
- ...codeceptPlugin.environments.codeceptjs.globals,
39
- },
40
- },
41
- // configure plugin rules
42
- rules: {
43
- // recommended rules
44
- ...codeceptPlugin.configs.recommended.rules,
45
- // extra rules
46
- "new-cap": ["error", {
47
- capIsNewExceptions: ["After", "AfterSuite", "Before", "BeforeSuite", "Feature", "Scenario"],
48
- }],
49
- "no-restricted-properties": ["warn", { object: "Scenario", property: "todo", message: "Unexpected unimplemented test." }],
50
- "codeceptjs/no-skipped-tests": "warn",
51
- // custom rules
52
- ...rules,
53
- },
26
+ return concatConfigs(
27
+ // "codecept" plugin
28
+ createConfig(options, {
29
+ // register rule implementations of the plugins
30
+ plugins: {
31
+ codeceptjs: codeceptPlugin,
54
32
  },
55
- {
56
- files,
57
- ignores,
58
- ...chaiExpectPlugin.configs["recommended-flat"],
33
+ // register global symbols of CodeceptJS
34
+ languageOptions: {
35
+ globals: codeceptPlugin.environments.codeceptjs.globals,
59
36
  },
60
- ];
37
+ // recommended rules
38
+ rules: codeceptPlugin.configs.recommended.rules,
39
+ }),
40
+ // "chai-expect" plugin
41
+ createConfig(options, chaiExpectPlugin.configs["recommended-flat"]),
42
+ // custom rules
43
+ customRules(options, {
44
+ "new-cap": ["error", {
45
+ capIsNewExceptions: ["After", "AfterSuite", "Before", "BeforeSuite", "Feature", "Scenario"],
46
+ }],
47
+ "no-restricted-properties": ["warn", { object: "Scenario", property: "todo", message: "Unexpected unimplemented test." }],
48
+ "codeceptjs/no-skipped-tests": "warn",
49
+ }));
61
50
  }
@@ -1,4 +1,5 @@
1
1
  import eslintPlugin from "eslint-plugin-eslint-plugin";
2
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
2
3
  // exports ====================================================================
3
4
  /**
4
5
  * Adds linter rules for ESLint plugin implementations.
@@ -13,22 +14,9 @@ import eslintPlugin from "eslint-plugin-eslint-plugin";
13
14
  * An array of configuration objects to be added to the flat configuration.
14
15
  */
15
16
  export default function eslint(options) {
16
- // configuration properties
17
- const { files, ignores = [], rules = {} } = options;
18
- // the plugin configuration
19
- const pluginConfig = eslintPlugin.configs["flat/rules-recommended"];
20
- return [
21
- // register rule implementations and recommended rules
22
- {
23
- files,
24
- ignores,
25
- ...pluginConfig,
26
- },
27
- // reconfigure plugin rules
28
- {
29
- files,
30
- ignores,
31
- rules,
32
- },
33
- ];
17
+ return concatConfigs(
18
+ // register rule implementations and recommended rules
19
+ createConfig(options, eslintPlugin.configs["flat/rules-recommended"]),
20
+ // custom rules
21
+ customRules(options));
34
22
  }
@@ -1,4 +1,5 @@
1
1
  import jestPlugin from "eslint-plugin-jest";
2
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
2
3
  // functions ==================================================================
3
4
  /**
4
5
  * Creates configuration objects with global symbols and linter rules for unit
@@ -14,36 +15,29 @@ import jestPlugin from "eslint-plugin-jest";
14
15
  * An array of configuration objects to be added to the flat configuration.
15
16
  */
16
17
  export default function jest(options) {
17
- // config properties
18
- const { files, ignores = [], rules } = options;
19
- return [{
20
- files,
21
- ignores,
22
- // register rule implementations, globals
23
- ...jestPlugin.configs["flat/recommended"],
24
- // configure plugin rules
25
- rules: {
26
- // recommended rules
27
- ...jestPlugin.configs["flat/recommended"].rules,
28
- ...jestPlugin.configs["flat/style"].rules,
29
- // extra rules
30
- "jest/consistent-test-it": ["error", { fn: "it" }],
31
- "jest/no-commented-out-tests": "error",
32
- "jest/no-conditional-expect": "off",
33
- "jest/no-confusing-set-timeout": "error",
34
- "jest/no-duplicate-hooks": "error",
35
- "jest/no-test-return-statement": "error",
36
- "jest/prefer-comparison-matcher": "error",
37
- "jest/prefer-equality-matcher": "error",
38
- "jest/prefer-expect-resolves": "error",
39
- "jest/prefer-hooks-on-top": "error",
40
- "jest/prefer-lowercase-title": "error",
41
- "jest/prefer-mock-promise-shorthand": "error",
42
- "jest/prefer-spy-on": "error",
43
- "jest/prefer-todo": "error",
44
- "jest/require-top-level-describe": "error",
45
- // custom rules
46
- ...rules,
47
- },
48
- }];
18
+ return concatConfigs(
19
+ // register rule implementations, globals, and recommended rules
20
+ createConfig(options, jestPlugin.configs["flat/recommended"]),
21
+ // add recommended stylistic rules
22
+ createConfig(options, {
23
+ rules: jestPlugin.configs["flat/style"].rules,
24
+ }),
25
+ // custom rules
26
+ customRules(options, {
27
+ "jest/consistent-test-it": ["error", { fn: "it" }],
28
+ "jest/no-commented-out-tests": "error",
29
+ "jest/no-conditional-expect": "off",
30
+ "jest/no-confusing-set-timeout": "error",
31
+ "jest/no-duplicate-hooks": "error",
32
+ "jest/no-test-return-statement": "error",
33
+ "jest/prefer-comparison-matcher": "error",
34
+ "jest/prefer-equality-matcher": "error",
35
+ "jest/prefer-expect-resolves": "error",
36
+ "jest/prefer-hooks-on-top": "error",
37
+ "jest/prefer-lowercase-title": "error",
38
+ "jest/prefer-mock-promise-shorthand": "error",
39
+ "jest/prefer-spy-on": "error",
40
+ "jest/prefer-todo": "error",
41
+ "jest/require-top-level-describe": "error",
42
+ }));
49
43
  }
@@ -1,18 +1,13 @@
1
1
  import type { TSESLint } from "@typescript-eslint/utils";
2
- import type { LanguageOptions, EnvBaseOptions, EnvRestrictedOptions } from "../shared/env-utils.js";
2
+ import type { LanguageOptions, EnvRestrictedOptions } from "../shared/env-utils.js";
3
3
  /**
4
4
  * Configuration options for the environment preset "env.node".
5
5
  */
6
- export interface EnvNodeOptions extends EnvBaseOptions {
6
+ export interface EnvNodeOptions extends EnvRestrictedOptions {
7
7
  /**
8
8
  * The module mode used by the linted files. Default value is "module".
9
9
  */
10
10
  sourceType?: LanguageOptions["sourceType"];
11
- /**
12
- * All globals, imports, properties, and syntax constructs to be banned for
13
- * the files included by the environment.
14
- */
15
- restricted?: EnvRestrictedOptions;
16
11
  }
17
12
  /**
18
13
  * Creates configuration objects with global symbols and linter rules for
@@ -1,5 +1,5 @@
1
1
  import nodePlugin from "eslint-plugin-n";
2
- import { generateRestrictedRules } from "../shared/env-utils.js";
2
+ import { concatConfigs, createConfig, restrictedRules, customRules } from "../shared/env-utils.js";
3
3
  // functions ==================================================================
4
4
  /**
5
5
  * Creates configuration objects with global symbols and linter rules for
@@ -15,37 +15,23 @@ import { generateRestrictedRules } from "../shared/env-utils.js";
15
15
  * An array of configuration objects to be added to the flat configuration.
16
16
  */
17
17
  export default function node(options) {
18
- // configuration properties
19
- const { files, ignores = [], sourceType = "module", rules } = options;
20
- // the plugin configuration
21
- const configKey = (sourceType === "commonjs") ? "flat/recommended-script" : "flat/recommended-module";
22
- const nodeConfig = nodePlugin.configs[configKey];
23
- // generate the "no-restricted-?" rules according to passed configuration
24
- const restricted = generateRestrictedRules({}, options?.restricted);
25
- return [
26
- // register rule implementations
27
- {
28
- files,
29
- ignores,
30
- ...nodeConfig,
31
- settings: {
32
- node: {
33
- tryExtensions: [".js", ".ts", ".d.ts"], // automatically add missing extensions in imports
34
- },
35
- },
36
- },
37
- // reconfigure plugin rules
38
- {
39
- files,
40
- ignores,
41
- rules: {
42
- "n/no-unsupported-features/node-builtins": ["error", { allowExperimental: true }],
43
- "n/prefer-node-protocol": "error",
44
- ...restricted.rules,
45
- ...rules,
18
+ // the plugin configuration key, according to source module type
19
+ const configKey = (options.sourceType === "commonjs") ? "flat/recommended-script" : "flat/recommended-module";
20
+ return concatConfigs(
21
+ // register rule implementations
22
+ createConfig(options, {
23
+ ...nodePlugin.configs[configKey],
24
+ settings: {
25
+ node: {
26
+ tryExtensions: [".js", ".ts", ".d.ts"], // automatically add missing extensions in imports
46
27
  },
47
28
  },
48
- // "no-restricted-?" rules overrides for specific files
49
- ...restricted.overrides,
50
- ];
29
+ }),
30
+ // generate the "no-restricted-?" rules according to passed configuration
31
+ restrictedRules(options),
32
+ // custom rules
33
+ customRules(options, {
34
+ "n/no-unsupported-features/node-builtins": ["error", { allowExperimental: true }],
35
+ "n/prefer-node-protocol": "error",
36
+ }));
51
37
  }
@@ -1,3 +1,4 @@
1
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
1
2
  import noAmdModuleDirective from "../rules/no-amd-module-directive.js";
2
3
  import noInvalidModules from "../rules/no-invalid-modules.js";
3
4
  // exports ====================================================================
@@ -11,25 +12,21 @@ import noInvalidModules from "../rules/no-invalid-modules.js";
11
12
  * An array of configuration objects to be added to the flat configuration.
12
13
  */
13
14
  export default function project(options) {
14
- // configuration properties
15
- const { files, ignores = [], rules, ...rest } = options;
16
- return [{
17
- files,
18
- ignores,
19
- // register rule implementations
20
- plugins: {
21
- "env-project": {
22
- rules: {
23
- "no-amd-module-directive": noAmdModuleDirective,
24
- "no-invalid-modules": noInvalidModules,
25
- },
15
+ return concatConfigs(
16
+ // register rule implementations
17
+ createConfig(options, {
18
+ plugins: {
19
+ "env-project": {
20
+ rules: {
21
+ "no-amd-module-directive": noAmdModuleDirective,
22
+ "no-invalid-modules": noInvalidModules,
26
23
  },
27
24
  },
28
- // configure rules
29
- rules: {
30
- "env-project/no-amd-module-directive": "error",
31
- "env-project/no-invalid-modules": ["error", rest],
32
- ...rules,
33
- },
34
- }];
25
+ },
26
+ }),
27
+ // custom rules
28
+ customRules(options, {
29
+ "env-project/no-amd-module-directive": "error",
30
+ "env-project/no-invalid-modules": ["error", options],
31
+ }));
35
32
  }
@@ -5,6 +5,7 @@ import reactRefreshPlugin from "eslint-plugin-react-refresh";
5
5
  import jsxExpressionsPlugin from "eslint-plugin-jsx-expressions";
6
6
  import jsxA11yPlugin from "eslint-plugin-jsx-a11y";
7
7
  import { fixupPluginRules } from "@eslint/compat";
8
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
8
9
  // functions ==================================================================
9
10
  /**
10
11
  * Creates configuration objects with linter rules for ReactJS.
@@ -24,68 +25,72 @@ import { fixupPluginRules } from "@eslint/compat";
24
25
  * An array of configuration objects to be added to the flat configuration.
25
26
  */
26
27
  export default function react(options) {
27
- // configuration properties
28
- const { files, ignores = [], rules, staticHooks = {} } = options;
29
- return [
30
- // configure plugins and rules for all source files (JSX and TSX)
31
- {
32
- files,
33
- ignores,
34
- // register rule implementations of the plugins
35
- plugins: {
36
- react: fixupPluginRules(reactPlugin), // https://github.com/jsx-eslint/eslint-plugin-react/issues/3699
37
- "react-hooks": reactHooksPlugin,
38
- "react-hooks-static-deps": fixupPluginRules(reactHooksStaticDepsPlugin), // https://github.com/stoikio/eslint-plugin-react-hooks-static-deps/issues/1
39
- "react-refresh": reactRefreshPlugin,
40
- "jsx-expressions": fixupPluginRules(jsxExpressionsPlugin), // https://github.com/hluisson/eslint-plugin-jsx-expressions/issues/18
41
- "jsx-a11y": jsxA11yPlugin,
42
- },
43
- settings: {
44
- react: {
45
- version: "detect",
46
- },
47
- },
48
- // enable JSX support
49
- languageOptions: {
50
- parserOptions: reactPlugin.configs.recommended.parserOptions,
51
- },
52
- // configure plugin rules
53
- rules: {
54
- // recommended rules
55
- ...reactPlugin.configs.recommended.rules,
56
- ...reactPlugin.configs["jsx-runtime"].rules,
57
- ...reactHooksPlugin.configs.recommended.rules,
58
- ...jsxA11yPlugin.flatConfigs.recommended.rules,
59
- // "react" plugin: change or disable a few recommended rules
60
- "react/hook-use-state": "error",
61
- "react/iframe-missing-sandbox": "error",
62
- "react/jsx-boolean-value": "error",
63
- "react/jsx-no-script-url": "error",
64
- "react/jsx-no-useless-fragment": "error",
65
- "react/no-danger": "error",
66
- "react/no-invalid-html-attribute": "error",
67
- "react/no-typos": "error",
68
- "react/prop-types": ["error", { skipUndeclared: true }],
69
- "react/style-prop-object": "error",
70
- "react/void-dom-elements-no-children": "error",
71
- // replace "react-hooks/exhaustive-deps" rule with advanced alternative
72
- "react-hooks/exhaustive-deps": "off",
73
- "react-hooks-static-deps/exhaustive-deps": ["error", { staticHooks }],
74
- // "react-refresh" plugin
75
- "react-refresh/only-export-components": ["error", { allowConstantExport: true }],
76
- // custom rules
77
- ...rules,
28
+ return concatConfigs(
29
+ // configure "react" plugin for all source files (JSX and TSX)
30
+ createConfig(options, {
31
+ // auto-detect installed React version
32
+ settings: {
33
+ react: {
34
+ version: "detect",
78
35
  },
79
36
  },
80
- // additional rules for TSX only
81
- {
82
- files,
83
- ignores: [...ignores, "**/*.{js,jsx}"],
84
- // configure plugin rules
85
- rules: {
86
- // replace "react/jsx-no-leaked-render" rule with advanced alternative
87
- "jsx-expressions/strict-logical-expressions": "error",
88
- },
37
+ // register rule implementations and language settings
38
+ ...reactPlugin.configs.flat.recommended,
39
+ rules: {
40
+ // recommended rules
41
+ ...reactPlugin.configs.flat.recommended.rules,
42
+ ...reactPlugin.configs.flat["jsx-runtime"].rules,
43
+ },
44
+ }),
45
+ // configure other plugins and rules for all source files (JSX and TSX)
46
+ createConfig(options, {
47
+ // register rule implementations of the plugins
48
+ plugins: {
49
+ "react-hooks": reactHooksPlugin,
50
+ "react-refresh": reactRefreshPlugin,
51
+ "jsx-expressions": fixupPluginRules(jsxExpressionsPlugin), // https://github.com/hluisson/eslint-plugin-jsx-expressions/issues/18
52
+ "jsx-a11y": jsxA11yPlugin,
53
+ },
54
+ // recommended rules
55
+ rules: {
56
+ ...reactHooksPlugin.configs.recommended.rules,
57
+ ...jsxA11yPlugin.flatConfigs.recommended.rules,
58
+ },
59
+ }),
60
+ // "react-hooks-static-deps" plugin
61
+ options.staticHooks && createConfig(options, {
62
+ plugins: {
63
+ "react-hooks-static-deps": fixupPluginRules(reactHooksStaticDepsPlugin), // https://github.com/stoikio/eslint-plugin-react-hooks-static-deps/issues/1
64
+ },
65
+ rules: {
66
+ "react-hooks/exhaustive-deps": "off",
67
+ "react-hooks-static-deps/exhaustive-deps": ["error", { staticHooks: options.staticHooks }],
68
+ },
69
+ }),
70
+ // additional rules for TSX only
71
+ createConfig(options, {
72
+ ignores: ["**/*.{js,jsx}"],
73
+ rules: {
74
+ // replace "react/jsx-no-leaked-render" rule with advanced alternative
75
+ "jsx-expressions/strict-logical-expressions": "error",
89
76
  },
90
- ];
77
+ }),
78
+ // custom rules
79
+ customRules(options, {
80
+ // "react" plugin
81
+ "react/hook-use-state": "error",
82
+ "react/iframe-missing-sandbox": "error",
83
+ "react/jsx-boolean-value": "error",
84
+ "react/jsx-no-script-url": "error",
85
+ "react/jsx-no-useless-fragment": "error",
86
+ "react/jsx-props-no-spread-multi": "error",
87
+ "react/no-danger": "error",
88
+ "react/no-invalid-html-attribute": "error",
89
+ "react/no-typos": "error",
90
+ "react/prop-types": ["error", { skipUndeclared: true }],
91
+ "react/style-prop-object": "error",
92
+ "react/void-dom-elements-no-children": "error",
93
+ // "react-refresh" plugin
94
+ "react-refresh/only-export-components": ["error", { allowConstantExport: true }],
95
+ }));
91
96
  }
@@ -1,3 +1,4 @@
1
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
1
2
  // functions ==================================================================
2
3
  /**
3
4
  * Creates configuration objects for TypeScript projects.
@@ -9,21 +10,15 @@
9
10
  * An array of configuration objects to be added to the flat configuration.
10
11
  */
11
12
  export default function tsconfig(options) {
12
- // configuration properties
13
- const { files, ignores = [], rules } = options;
14
- return [{
15
- files,
16
- ignores,
17
- // path to project configuration file
18
- languageOptions: {
19
- parserOptions: {
20
- project: options.project,
21
- },
13
+ return concatConfigs(
14
+ // path to project configuration file
15
+ createConfig(options, {
16
+ languageOptions: {
17
+ parserOptions: {
18
+ project: options.project,
22
19
  },
23
- // configure plugin rules
24
- rules: {
25
- // custom rules
26
- ...rules,
27
- },
28
- }];
20
+ },
21
+ }),
22
+ // custom rules
23
+ customRules(options));
29
24
  }
@@ -2,6 +2,7 @@ import vitestPlugin from "eslint-plugin-vitest";
2
2
  import jestDomPlugin from "eslint-plugin-jest-dom";
3
3
  import testingLibraryPlugin from "eslint-plugin-testing-library";
4
4
  import { fixupPluginRules } from "@eslint/compat";
5
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
5
6
  // functions ==================================================================
6
7
  /**
7
8
  * Creates configuration objects with global symbols and linter rules for unit
@@ -19,72 +20,56 @@ import { fixupPluginRules } from "@eslint/compat";
19
20
  * An array of configuration objects to be added to the flat configuration.
20
21
  */
21
22
  export default function vitest(options) {
22
- // configuration properties
23
- const { files, ignores = [], rules } = options;
24
- return [
25
- // "vitest" plugin
26
- {
27
- files,
28
- ignores,
29
- // register rule implementations of the plugins
30
- plugins: {
31
- vitest: vitestPlugin,
32
- },
33
- // register global symbols of Vitest
34
- languageOptions: {
35
- globals: vitestPlugin.environments.env.globals,
36
- },
37
- // configure plugin rules
38
- rules: {
39
- // recommended rules
40
- ...vitestPlugin.configs.recommended.rules,
41
- // extra rules
42
- "vitest/consistent-test-it": "error",
43
- "vitest/no-alias-methods": "error",
44
- "vitest/no-disabled-tests": "warn",
45
- "vitest/no-duplicate-hooks": "error",
46
- "vitest/no-focused-tests": "error",
47
- "vitest/no-standalone-expect": "error",
48
- "vitest/no-test-prefixes": "error",
49
- "vitest/no-test-return-statement": "error",
50
- "vitest/prefer-comparison-matcher": "error",
51
- "vitest/prefer-each": "error",
52
- "vitest/prefer-equality-matcher": "error",
53
- "vitest/prefer-expect-resolves": "error",
54
- "vitest/prefer-hooks-in-order": "error",
55
- "vitest/prefer-hooks-on-top": "error",
56
- "vitest/prefer-mock-promise-shorthand": "error",
57
- "vitest/prefer-spy-on": "error",
58
- "vitest/prefer-strict-equal": "error",
59
- "vitest/prefer-to-be": "error",
60
- "vitest/prefer-to-contain": "error",
61
- "vitest/prefer-to-have-length": "error",
62
- "vitest/require-top-level-describe": "error",
63
- // custom rules
64
- ...rules,
65
- },
23
+ return concatConfigs(
24
+ // "vitest" plugin
25
+ createConfig(options, {
26
+ // register rule implementations of the plugins
27
+ plugins: {
28
+ vitest: vitestPlugin,
66
29
  },
67
- // "jest-dom" plugin
68
- {
69
- files,
70
- ignores,
71
- ...jestDomPlugin.configs["flat/recommended"],
30
+ // register global symbols of Vitest
31
+ languageOptions: {
32
+ globals: vitestPlugin.environments.env.globals,
72
33
  },
73
- // "testing-library" plugin
74
- {
75
- files,
76
- ignores,
77
- // register rule implementations of the plugins
78
- plugins: {
79
- "testing-library": fixupPluginRules(testingLibraryPlugin), // https://github.com/testing-library/eslint-plugin-testing-library/issues/899
80
- },
81
- // configure plugin rules
82
- rules: {
83
- // recommended rules
84
- ...testingLibraryPlugin.configs.react.rules,
85
- // extra rules
86
- "testing-library/no-node-access": ["error", { allowContainerFirstChild: true }],
87
- },
34
+ // recommended rules
35
+ rules: vitestPlugin.configs.recommended.rules,
36
+ }),
37
+ // "jest-dom" plugin
38
+ createConfig(options, jestDomPlugin.configs["flat/recommended"]),
39
+ // "testing-library" plugin
40
+ createConfig(options, {
41
+ // register rule implementations of the plugins
42
+ plugins: {
43
+ "testing-library": fixupPluginRules(testingLibraryPlugin), // https://github.com/testing-library/eslint-plugin-testing-library/issues/899
88
44
  },
89
- ];
45
+ // recommended rules
46
+ rules: testingLibraryPlugin.configs.react.rules,
47
+ }),
48
+ // custom rules
49
+ customRules(options, {
50
+ // "vitest" plugin
51
+ "vitest/consistent-test-it": "error",
52
+ "vitest/no-alias-methods": "error",
53
+ "vitest/no-disabled-tests": "warn",
54
+ "vitest/no-duplicate-hooks": "error",
55
+ "vitest/no-focused-tests": "error",
56
+ "vitest/no-standalone-expect": "error",
57
+ "vitest/no-test-prefixes": "error",
58
+ "vitest/no-test-return-statement": "error",
59
+ "vitest/prefer-comparison-matcher": "error",
60
+ "vitest/prefer-each": "error",
61
+ "vitest/prefer-equality-matcher": "error",
62
+ "vitest/prefer-expect-resolves": "error",
63
+ "vitest/prefer-hooks-in-order": "error",
64
+ "vitest/prefer-hooks-on-top": "error",
65
+ "vitest/prefer-mock-promise-shorthand": "error",
66
+ "vitest/prefer-spy-on": "error",
67
+ "vitest/prefer-strict-equal": "error",
68
+ "vitest/prefer-to-be": "error",
69
+ "vitest/prefer-to-contain": "error",
70
+ "vitest/prefer-to-have-length": "error",
71
+ "vitest/require-top-level-describe": "error",
72
+ // "testing-library" plugin
73
+ "testing-library/no-node-access": ["error", { allowContainerFirstChild: true }],
74
+ }));
90
75
  }
@@ -126,10 +126,10 @@ export interface EnvRestrictedItems {
126
126
  export interface EnvRestrictedOverride extends EnvFilesOptions, EnvRestrictedItems {
127
127
  }
128
128
  /**
129
- * Configuration options for banned globals, imports, properties, and syntax
130
- * constructs in the environment.
129
+ * Type shape of a dedicated environment option "restricted" with settings for
130
+ * banned globals, imports, properties, and syntax constructs.
131
131
  */
132
- export interface EnvRestrictedOptions extends EnvRestrictedItems {
132
+ export interface EnvRestrictedOption extends EnvRestrictedItems {
133
133
  /**
134
134
  * Whether the environment supports native decorators. In this case, it
135
135
  * will be required to replace TypeScript decorated `private` methods with
@@ -146,9 +146,16 @@ export interface EnvRestrictedOptions extends EnvRestrictedItems {
146
146
  */
147
147
  overrides?: EnvRestrictedOverride[];
148
148
  }
149
- export interface EnvRestrictedRulesResult {
150
- rules: TSESLint.FlatConfig.Rules;
151
- overrides: TSESLint.FlatConfig.ConfigArray;
149
+ /**
150
+ * Shared options for an environment preset: include and exclude files, add
151
+ * more linter rules, and settings for restricted items.
152
+ */
153
+ export interface EnvRestrictedOptions extends EnvBaseOptions {
154
+ /**
155
+ * All globals, imports, properties, and syntax constructs to be banned for
156
+ * the files included by the environment.
157
+ */
158
+ restricted?: EnvRestrictedOption;
152
159
  }
153
160
  /**
154
161
  * Shared options for the core rule `no-unused-vars`, and the plugin rule
@@ -161,16 +168,61 @@ export declare const NO_UNUSED_VARS_OPTIONS: {
161
168
  caughtErrors: string;
162
169
  ignoreRestSiblings: boolean;
163
170
  };
171
+ /**
172
+ * Concatenates multiple configuration objects or arrays into an array while
173
+ * skipping all falsy parameters.
174
+ *
175
+ * @param configs
176
+ * The configuration objects to be concatenated.
177
+ *
178
+ * @returns
179
+ * The concatenated configuration array.
180
+ */
181
+ export declare const concatConfigs: (...entries: (TSESLint.FlatConfig.Config | TSESLint.FlatConfig.Config[] | undefined)[]) => TSESLint.FlatConfig.Config[];
182
+ /**
183
+ * Creates a flat configuration object with "files" and "ignores" settings from
184
+ * an environment's "options" object.
185
+ *
186
+ * @param options
187
+ * The environment options containing "files" and "ignores" settings.
188
+ *
189
+ * @param config
190
+ * The remaining properties of the flat configuration to be built. Additional
191
+ * "files" and "ignores" properties will be merged with the settings from
192
+ * "options".
193
+ *
194
+ * @returns
195
+ * The resulting flat configuration object.
196
+ */
197
+ export declare function createConfig(options: EnvFilesOptions, config: TSESLint.FlatConfig.Config): TSESLint.FlatConfig.Config;
164
198
  /**
165
199
  * Generates various "no-restricted-?" rules from the passed configuration.
166
200
  *
201
+ * @param options
202
+ * The environment options containing "files", "ignores", and "restricted"
203
+ * settings.
204
+ *
167
205
  * @param fixed
168
206
  * The fixed restricted items provided by the environment preset.
169
207
  *
208
+ * @returns
209
+ * The flat configuration objects needed to forbid the restricted items.
210
+ */
211
+ export declare function restrictedRules(options: EnvRestrictedOptions, fixed?: EnvRestrictedItems): TSESLint.FlatConfig.ConfigArray;
212
+ /**
213
+ * Creates a flat configuration object with `files`, `ignores`, and `rules`
214
+ * settings from an environment's `options` object.
215
+ *
170
216
  * @param options
171
- * The custom configuration passed to an environment preset.
217
+ * The environment options containing `files`,`ignores`, and `rules` settings.
218
+ *
219
+ * @param rules
220
+ * Hard-coded rule settings to be configured by the environment itself. These
221
+ * rule settings will precede the rules contained in "options", in order to
222
+ * allow to override them.
172
223
  *
173
224
  * @returns
174
- * The generated linter rules to forbid the restricted items.
225
+ * The resulting flat configuration object, if the environment options contain
226
+ * custom rule settings, otherwise `undefined`.
175
227
  */
176
- export declare function generateRestrictedRules(fixed: EnvRestrictedItems, options?: EnvRestrictedOptions): EnvRestrictedRulesResult;
228
+ export declare function customRules(options: EnvBaseOptions, rules?: TSESLint.FlatConfig.Rules): TSESLint.FlatConfig.Config | undefined;
@@ -12,16 +12,17 @@ export const NO_UNUSED_VARS_OPTIONS = {
12
12
  };
13
13
  // functions ==================================================================
14
14
  /**
15
- * Concatenates the elements of multiple arrays. Skips `undefined` parameters.
15
+ * Concatenates and flattens multiple elements or arrays into a single array
16
+ * while skipping all falsy parameters.
16
17
  *
17
- * @param arrays
18
- * The arrays to be concatenated.
18
+ * @param entries
19
+ * The elements or arrays to be concatenated.
19
20
  *
20
21
  * @returns
21
- * The concatenated arrays.
22
+ * The concatenated and flattened array.
22
23
  */
23
- function concatArrays(...arrays) {
24
- return arrays.flatMap(array => array || []);
24
+ function flatten(...entries) {
25
+ return entries.flatMap(array => array || []);
25
26
  }
26
27
  /**
27
28
  * Creates a rules record for all restricted items.
@@ -48,45 +49,99 @@ function createRulesRecord(generator) {
48
49
  return rules;
49
50
  }
50
51
  // ----------------------------------------------------------------------------
52
+ /**
53
+ * Concatenates multiple configuration objects or arrays into an array while
54
+ * skipping all falsy parameters.
55
+ *
56
+ * @param configs
57
+ * The configuration objects to be concatenated.
58
+ *
59
+ * @returns
60
+ * The concatenated configuration array.
61
+ */
62
+ export const concatConfigs = (flatten);
63
+ /**
64
+ * Creates a flat configuration object with "files" and "ignores" settings from
65
+ * an environment's "options" object.
66
+ *
67
+ * @param options
68
+ * The environment options containing "files" and "ignores" settings.
69
+ *
70
+ * @param config
71
+ * The remaining properties of the flat configuration to be built. Additional
72
+ * "files" and "ignores" properties will be merged with the settings from
73
+ * "options".
74
+ *
75
+ * @returns
76
+ * The resulting flat configuration object.
77
+ */
78
+ export function createConfig(options, config) {
79
+ return {
80
+ ...config,
81
+ files: flatten(options.files, config.files),
82
+ ignores: flatten(options.ignores, config.ignores),
83
+ };
84
+ }
51
85
  /**
52
86
  * Generates various "no-restricted-?" rules from the passed configuration.
53
87
  *
88
+ * @param options
89
+ * The environment options containing "files", "ignores", and "restricted"
90
+ * settings.
91
+ *
54
92
  * @param fixed
55
93
  * The fixed restricted items provided by the environment preset.
56
94
  *
57
- * @param options
58
- * The custom configuration passed to an environment preset.
59
- *
60
95
  * @returns
61
- * The generated linter rules to forbid the restricted items.
96
+ * The flat configuration objects needed to forbid the restricted items.
62
97
  */
63
- export function generateRestrictedRules(fixed, options) {
98
+ export function restrictedRules(options, fixed) {
99
+ const { restricted = {} } = options;
64
100
  const RESTRICTED_GLOBALS = [
65
101
  { name: "isFinite", message: "Use 'Number.isFinite' instead." },
66
102
  { name: "isNaN", message: "Use 'Number.isNaN' instead." },
67
103
  ];
68
104
  const RESTRICTED_SYNTAX = [
69
105
  { selector: ":matches(PropertyDefinition, MethodDefinition[kind!='constructor'])[accessibility='public']", message: "Remove 'public' keyword." },
70
- { selector: ":matches(PropertyDefinition, MethodDefinition[kind!='constructor'])[accessibility='private']" + (options?.nativeDecorators ? "" : "[decorators.length=0]"), message: "Use #private syntax instead." },
106
+ { selector: ":matches(PropertyDefinition, MethodDefinition[kind!='constructor'])[accessibility='private']" + (restricted.nativeDecorators ? "" : "[decorators.length=0]"), message: "Use #private syntax instead." },
71
107
  { selector: "MethodDefinition[kind='constructor'] TSParameterProperty[accessibility]", message: "Use explicit class properties." },
72
108
  ];
73
109
  // restricted items for all files in the environment
74
110
  const items = {
75
- globals: concatArrays(RESTRICTED_GLOBALS, fixed.globals, options?.globals),
76
- imports: concatArrays(fixed.imports, options?.imports),
77
- properties: concatArrays(fixed.properties, options?.properties),
78
- syntax: concatArrays(RESTRICTED_SYNTAX, fixed.syntax, options?.syntax),
111
+ globals: flatten(RESTRICTED_GLOBALS, fixed?.globals, restricted.globals),
112
+ imports: flatten(fixed?.imports, restricted.imports),
113
+ properties: flatten(fixed?.properties, restricted.properties),
114
+ syntax: flatten(RESTRICTED_SYNTAX, fixed?.syntax, restricted.syntax),
79
115
  };
116
+ // generate the configuration objects
117
+ return concatConfigs(
80
118
  // base rules for all files in the environment
81
- const rules = createRulesRecord(key => items[key]);
119
+ createConfig(options, {
120
+ rules: createRulesRecord(key => items[key]),
121
+ }),
82
122
  // generate the override entries (join with base items)
83
- const overrides = [];
84
- for (const override of options?.overrides ?? []) {
85
- overrides.push({
86
- files: override.files,
87
- ignores: override.ignores ?? [],
88
- rules: createRulesRecord(key => concatArrays(items[key], override[key])),
89
- });
90
- }
91
- return { rules, overrides };
123
+ restricted.overrides?.map(override => createConfig(override, {
124
+ rules: createRulesRecord(key => flatten(items[key], override[key])),
125
+ })));
126
+ }
127
+ /**
128
+ * Creates a flat configuration object with `files`, `ignores`, and `rules`
129
+ * settings from an environment's `options` object.
130
+ *
131
+ * @param options
132
+ * The environment options containing `files`,`ignores`, and `rules` settings.
133
+ *
134
+ * @param rules
135
+ * Hard-coded rule settings to be configured by the environment itself. These
136
+ * rule settings will precede the rules contained in "options", in order to
137
+ * allow to override them.
138
+ *
139
+ * @returns
140
+ * The resulting flat configuration object, if the environment options contain
141
+ * custom rule settings, otherwise `undefined`.
142
+ */
143
+ export function customRules(options, rules) {
144
+ return (rules || options.rules) && createConfig(options, {
145
+ rules: { ...rules, ...options.rules },
146
+ });
92
147
  }
@@ -37,6 +37,7 @@ function configure(options?: ConfigureOptions): Linter.FlatConfig[]
37
37
  | `language` | `LanguageOptions` | | Configuration options for language and project setup. |
38
38
  | `language.ecmaVersion` | `number` | `2022` | The ECMAScript version to be used in the project (version or year). |
39
39
  | `language.sourceType` | `"module"\|"commonjs"` | `"module"` | Specifies how to treat `.js`, `.jsx`, `.ts`, and `.tsx` files. |
40
+ | `language.nativeDecorators` | `boolean` | `false` | Whether to support native ES decorators in JavaScript code (via Babel plugin). Does not affect TypeScript code which uses an own parser aware of the decorator syntax. |
40
41
  | `stylistic` | `StylisticOptions` | | Configuration options for code style. |
41
42
  | `stylistic.indent` | `number` | `2` | Default indentation size (number of space characters). Will be applied to JavaScript, TypeScript, JSON, and YAML files, as well as JSX markup. |
42
43
  | `stylistic.semi` | `boolean` | `false` | Specifies whether to require semicolons following all statements (`true`), or to force to omit semicolons if possible according to ASI rules (`false`). |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@open-xchange/linter-presets",
4
- "version": "0.1.4",
4
+ "version": "0.1.5",
5
5
  "description": "Configuration presets for ESLint and StyleLint",
6
6
  "repository": {
7
7
  "url": "https://gitlab.open-xchange.com/fspd/npm-packages/linter-presets"
@@ -23,7 +23,7 @@
23
23
  "*.{js,ts,json}": "yarn lint"
24
24
  },
25
25
  "dependencies": {
26
- "@babel/core": "7.24.8",
26
+ "@babel/core": "7.24.9",
27
27
  "@babel/eslint-parser": "7.24.8",
28
28
  "@babel/plugin-proposal-decorators": "7.24.7",
29
29
  "@eslint-community/eslint-plugin-eslint-comments": "4.3.0",
@@ -40,17 +40,17 @@
40
40
  "eslint-plugin-import": "2.29.1",
41
41
  "eslint-plugin-jest": "28.6.0",
42
42
  "eslint-plugin-jest-dom": "5.4.0",
43
- "eslint-plugin-jsdoc": "48.7.0",
43
+ "eslint-plugin-jsdoc": "48.8.3",
44
44
  "eslint-plugin-jsonc": "2.16.0",
45
45
  "eslint-plugin-jsx-a11y": "6.9.0",
46
46
  "eslint-plugin-jsx-expressions": "1.3.2",
47
47
  "eslint-plugin-license-header": "0.6.1",
48
48
  "eslint-plugin-n": "17.9.0",
49
- "eslint-plugin-promise": "6.4.0",
50
- "eslint-plugin-react": "7.34.4",
49
+ "eslint-plugin-promise": "6.6.0",
50
+ "eslint-plugin-react": "7.35.0",
51
51
  "eslint-plugin-react-hooks": "4.6.2",
52
52
  "eslint-plugin-react-hooks-static-deps": "1.0.7",
53
- "eslint-plugin-react-refresh": "0.4.8",
53
+ "eslint-plugin-react-refresh": "0.4.9",
54
54
  "eslint-plugin-testing-library": "6.2.2",
55
55
  "eslint-plugin-vitest": "0.5.4",
56
56
  "eslint-plugin-yml": "1.14.0",
@@ -61,18 +61,18 @@
61
61
  "stylelint-config-standard-less": "3.0.1",
62
62
  "stylelint-config-standard-scss": "13.1.0",
63
63
  "stylelint-plugin-license-header": "1.0.3",
64
- "typescript-eslint": "7.16.0"
64
+ "typescript-eslint": "7.17.0"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@types/confusing-browser-globals": "1.0.3",
68
68
  "@types/eslint__js": "8.42.3",
69
69
  "@types/picomatch": "3.0.0",
70
- "@typescript-eslint/utils": "7.16.0",
70
+ "@typescript-eslint/utils": "7.17.0",
71
71
  "eslint": "9.7.0",
72
- "husky": "9.0.11",
72
+ "husky": "9.1.1",
73
73
  "jest": "29.7.0",
74
74
  "stylelint": "16.7.0",
75
- "typescript": "5.5.3"
75
+ "typescript": "5.5.4"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "eslint": "^9.6",