@open-xchange/linter-presets 0.1.4 → 0.1.6

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.
@@ -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.
@@ -17,75 +18,79 @@ import { fixupPluginRules } from "@eslint/compat";
17
18
  * - `eslint-plugin-jsx-expressions`
18
19
  * - `eslint-plugin-jsx-a11y`
19
20
  *
20
- * @param options
21
+ * @param envOptions
21
22
  * Configuration options for the environment.
22
23
  *
23
24
  * @returns
24
25
  * An array of configuration objects to be added to the flat configuration.
25
26
  */
26
- 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,
27
+ export default function react(envOptions) {
28
+ return concatConfigs(
29
+ // configure "react" plugin for all source files (JSX and TSX)
30
+ createConfig(envOptions, {
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(envOptions, {
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
+ envOptions.staticHooks && createConfig(envOptions, {
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: envOptions.staticHooks }],
68
+ },
69
+ }),
70
+ // additional rules for TSX only
71
+ createConfig(envOptions, {
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(envOptions, {
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
  }
@@ -12,10 +12,10 @@ export interface EnvTSConfigOptions extends EnvBaseOptions {
12
12
  /**
13
13
  * Creates configuration objects for TypeScript projects.
14
14
  *
15
- * @param options
15
+ * @param envOptions
16
16
  * Configuration options for the environment.
17
17
  *
18
18
  * @returns
19
19
  * An array of configuration objects to be added to the flat configuration.
20
20
  */
21
- export default function tsconfig(options: EnvTSConfigOptions): TSESLint.FlatConfig.ConfigArray;
21
+ export default function tsconfig(envOptions: EnvTSConfigOptions): TSESLint.FlatConfig.ConfigArray;
@@ -1,29 +1,24 @@
1
+ import { concatConfigs, createConfig, customRules } from "../shared/env-utils.js";
1
2
  // functions ==================================================================
2
3
  /**
3
4
  * Creates configuration objects for TypeScript projects.
4
5
  *
5
- * @param options
6
+ * @param envOptions
6
7
  * Configuration options for the environment.
7
8
  *
8
9
  * @returns
9
10
  * An array of configuration objects to be added to the flat configuration.
10
11
  */
11
- 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
- },
12
+ export default function tsconfig(envOptions) {
13
+ return concatConfigs(
14
+ // path to project configuration file
15
+ createConfig(envOptions, {
16
+ languageOptions: {
17
+ parserOptions: {
18
+ project: envOptions.project,
22
19
  },
23
- // configure plugin rules
24
- rules: {
25
- // custom rules
26
- ...rules,
27
- },
28
- }];
20
+ },
21
+ }),
22
+ // custom rules
23
+ customRules(envOptions));
29
24
  }
@@ -14,10 +14,10 @@ export interface EnvVitestOptions extends EnvBaseOptions {
14
14
  * - `eslint-plugin-jest-dom`
15
15
  * - `eslint-plugin-testing-library`
16
16
  *
17
- * @param options
17
+ * @param envOptions
18
18
  * Configuration options for the environment.
19
19
  *
20
20
  * @returns
21
21
  * An array of configuration objects to be added to the flat configuration.
22
22
  */
23
- export default function vitest(options: EnvVitestOptions): TSESLint.FlatConfig.ConfigArray;
23
+ export default function vitest(envOptions: EnvVitestOptions): TSESLint.FlatConfig.ConfigArray;
@@ -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
@@ -12,79 +13,63 @@ import { fixupPluginRules } from "@eslint/compat";
12
13
  * - `eslint-plugin-jest-dom`
13
14
  * - `eslint-plugin-testing-library`
14
15
  *
15
- * @param options
16
+ * @param envOptions
16
17
  * Configuration options for the environment.
17
18
  *
18
19
  * @returns
19
20
  * An array of configuration objects to be added to the flat configuration.
20
21
  */
21
- 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
- },
22
+ export default function vitest(envOptions) {
23
+ return concatConfigs(
24
+ // "vitest" plugin
25
+ createConfig(envOptions, {
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(envOptions, jestDomPlugin.configs["flat/recommended"]),
39
+ // "testing-library" plugin
40
+ createConfig(envOptions, {
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(envOptions, {
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
  }
@@ -1,6 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { posix, dirname, extname } from "node:path";
3
- import { packageUpSync } from "package-up";
3
+ import { findUpSync } from "find-up";
4
4
  import { AST_NODE_TYPES as NodeType, ESLintUtils } from "@typescript-eslint/utils";
5
5
  import { Schema, makeArray, toPosixPath, isFile, matchModuleName, getModuleName } from "../shared/rule-utils.js";
6
6
  // constants ==================================================================
@@ -47,8 +47,8 @@ export default ESLintUtils.RuleCreator.withoutDocs({
47
47
  // collect all globs for package members
48
48
  const packagesGlobs = Array.from(packagesMap.values(), settings => settings.src).flat();
49
49
  // resolve file name
50
- const packagePath = packageUpSync();
51
- const rootDir = packagePath && toPosixPath(dirname(packagePath));
50
+ const configPath = findUpSync("eslint.config.js");
51
+ const rootDir = configPath && toPosixPath(dirname(configPath));
52
52
  const fileName = toPosixPath(context.filename);
53
53
  if (!rootDir || !fileName.startsWith(rootDir + "/")) {
54
54
  throw new Error("invalid root directory");
@@ -86,7 +86,7 @@ export default ESLintUtils.RuleCreator.withoutDocs({
86
86
  return FILE_EXTENSIONS.some(ext => isFile(resolvedPath + "." + ext));
87
87
  };
88
88
  // returns whether the passed module name is an installed NPM package
89
- const requireModule = createRequire(packagePath);
89
+ const requireModule = createRequire(configPath);
90
90
  const packageExists = (moduleName) => {
91
91
  try {
92
92
  requireModule.resolve(moduleName);
@@ -110,7 +110,7 @@ export default ESLintUtils.RuleCreator.withoutDocs({
110
110
  // extract alias key, replace with alias path
111
111
  const [aliasKey, modulePath] = resolveAlias(moduleName);
112
112
  // whether the import is a known external module
113
- const isExternal = !aliasKey && matchModuleName(moduleName, options.external);
113
+ const isExternal = matchModuleName(moduleName, options.external);
114
114
  // whether the import is an installed NPM package
115
115
  const isPackage = !isExternal && !aliasKey && packageExists(moduleName);
116
116
  // check existence of source file
@@ -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 "envOptions" object.
185
+ *
186
+ * @param envOptions
187
+ * The environment options containing "files" and "ignores" settings.
188
+ *
189
+ * @param flatConfig
190
+ * Properties for the flat configuration to be built. Additional "files" and
191
+ * "ignores" properties will be merged with the settings from "envOptions".
192
+ *
193
+ * @returns
194
+ * The resulting flat configuration object.
195
+ */
196
+ export declare function createConfig(envOptions: EnvFilesOptions, flatConfig: TSESLint.FlatConfig.Config): TSESLint.FlatConfig.Config;
164
197
  /**
165
198
  * Generates various "no-restricted-?" rules from the passed configuration.
166
199
  *
200
+ * @param envOptions
201
+ * The environment options containing "files", "ignores", and "restricted"
202
+ * settings.
203
+ *
167
204
  * @param fixed
168
205
  * The fixed restricted items provided by the environment preset.
169
206
  *
170
- * @param options
171
- * The custom configuration passed to an environment preset.
207
+ * @returns
208
+ * The flat configuration objects needed to forbid the restricted items.
209
+ */
210
+ export declare function restrictedRules(envOptions: EnvRestrictedOptions, fixed?: EnvRestrictedItems): TSESLint.FlatConfig.ConfigArray;
211
+ /**
212
+ * Creates a flat configuration object with "files", "ignores", and "rules"
213
+ * settings from an environment's "envOptions" object.
214
+ *
215
+ * @param envOptions
216
+ * The environment options containing "files", "ignores", and "rules"
217
+ * 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 "envOptions", 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(envOptions: 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 "envOptions" object.
66
+ *
67
+ * @param envOptions
68
+ * The environment options containing "files" and "ignores" settings.
69
+ *
70
+ * @param flatConfig
71
+ * Properties for the flat configuration to be built. Additional "files" and
72
+ * "ignores" properties will be merged with the settings from "envOptions".
73
+ *
74
+ * @returns
75
+ * The resulting flat configuration object.
76
+ */
77
+ export function createConfig(envOptions, flatConfig) {
78
+ return {
79
+ ...flatConfig,
80
+ files: flatten(envOptions.files, flatConfig.files),
81
+ ignores: flatten(envOptions.ignores, flatConfig.ignores),
82
+ };
83
+ }
51
84
  /**
52
85
  * Generates various "no-restricted-?" rules from the passed configuration.
53
86
  *
87
+ * @param envOptions
88
+ * The environment options containing "files", "ignores", and "restricted"
89
+ * settings.
90
+ *
54
91
  * @param fixed
55
92
  * The fixed restricted items provided by the environment preset.
56
93
  *
57
- * @param options
58
- * The custom configuration passed to an environment preset.
59
- *
60
94
  * @returns
61
- * The generated linter rules to forbid the restricted items.
95
+ * The flat configuration objects needed to forbid the restricted items.
62
96
  */
63
- export function generateRestrictedRules(fixed, options) {
97
+ export function restrictedRules(envOptions, fixed) {
98
+ const { restricted = {} } = envOptions;
64
99
  const RESTRICTED_GLOBALS = [
65
100
  { name: "isFinite", message: "Use 'Number.isFinite' instead." },
66
101
  { name: "isNaN", message: "Use 'Number.isNaN' instead." },
67
102
  ];
68
103
  const RESTRICTED_SYNTAX = [
69
104
  { 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." },
105
+ { selector: ":matches(PropertyDefinition, MethodDefinition[kind!='constructor'])[accessibility='private']" + (restricted.nativeDecorators ? "" : "[decorators.length=0]"), message: "Use #private syntax instead." },
71
106
  { selector: "MethodDefinition[kind='constructor'] TSParameterProperty[accessibility]", message: "Use explicit class properties." },
72
107
  ];
73
108
  // restricted items for all files in the environment
74
109
  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),
110
+ globals: flatten(RESTRICTED_GLOBALS, fixed?.globals, restricted.globals),
111
+ imports: flatten(fixed?.imports, restricted.imports),
112
+ properties: flatten(fixed?.properties, restricted.properties),
113
+ syntax: flatten(RESTRICTED_SYNTAX, fixed?.syntax, restricted.syntax),
79
114
  };
115
+ // generate the configuration objects
116
+ return concatConfigs(
80
117
  // base rules for all files in the environment
81
- const rules = createRulesRecord(key => items[key]);
118
+ createConfig(envOptions, {
119
+ rules: createRulesRecord(key => items[key]),
120
+ }),
82
121
  // 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 };
122
+ restricted.overrides?.map(override => createConfig(override, {
123
+ rules: createRulesRecord(key => flatten(items[key], override[key])),
124
+ })));
125
+ }
126
+ /**
127
+ * Creates a flat configuration object with "files", "ignores", and "rules"
128
+ * settings from an environment's "envOptions" object.
129
+ *
130
+ * @param envOptions
131
+ * The environment options containing "files", "ignores", and "rules"
132
+ * 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 "envOptions", 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(envOptions, rules) {
144
+ return (rules || envOptions.rules) && createConfig(envOptions, {
145
+ rules: { ...rules, ...envOptions.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`). |