eslint-config-nick2bad4u 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,11 +13,11 @@ parsers that the shared config enables.
13
13
 
14
14
  ## Requirements
15
15
 
16
- | Tool | Supported range | Why it is required |
17
- | --- | --- | --- |
18
- | Node.js | `>=22.0.0` | Runtime for ESLint, the config package, and repository scripts. |
19
- | ESLint | `^10.4.0` | Peer dependency supplied by each consuming project. |
20
- | TypeScript | `^5.0.0 \|\| ^6.0.3` | Peer dependency used by TypeScript-aware lint rules. |
16
+ | Tool | Supported range | Why it is required |
17
+ | ---------- | -------------------- | --------------------------------------------------------------- |
18
+ | Node.js | `>=22.0.0` | Runtime for ESLint, the config package, and repository scripts. |
19
+ | ESLint | `^10.4.0` | Peer dependency supplied by each consuming project. |
20
+ | TypeScript | `^5.0.0 \|\| ^6.0.3` | Peer dependency used by TypeScript-aware lint rules. |
21
21
 
22
22
  Repository development also expects npm `>=11.0.0`; consumers can use the package
23
23
  with whatever package manager their project supports.
@@ -48,13 +48,13 @@ spreading it lets you append local overrides without replacing the shared config
48
48
  import nick2bad4u from "eslint-config-nick2bad4u";
49
49
 
50
50
  export default [
51
- ...nick2bad4u.configs.all,
52
- {
53
- name: "Local overrides",
54
- rules: {
55
- "no-console": "off",
56
- },
57
- },
51
+ ...nick2bad4u.configs.all,
52
+ {
53
+ name: "Local overrides",
54
+ rules: {
55
+ "no-console": "off",
56
+ },
57
+ },
58
58
  ];
59
59
  ```
60
60
 
@@ -73,15 +73,15 @@ For migration steps from an existing hand-written config, see the
73
73
 
74
74
  Long-form project documentation lives in [`docs/`](./docs/index.md).
75
75
 
76
- | Guide | Use it for |
77
- | --- | --- |
78
- | [Configuration](./docs/configuration.md) | `createConfig()`, presets, plugin replacement, and environment variables. |
79
- | [Migration](./docs/migration.md) | Moving a project from a hand-written flat config to this package. |
80
- | [Contributing](./CONTRIBUTING.md) | Local development workflow and pull request expectations. |
81
- | [Maintainer guide](./docs/maintainer-guide.md) | Rule, preset, dependency, and release maintenance. |
82
- | [Support](./SUPPORT.md) | Issue triage and reproduction details. |
83
- | [Security](./SECURITY.md) | Private vulnerability reporting. |
84
- | [Code of conduct](./CODE_OF_CONDUCT.md) | Participation standards for the project. |
76
+ | Guide | Use it for |
77
+ | ---------------------------------------------- | ------------------------------------------------------------------------- |
78
+ | [Configuration](./docs/configuration.md) | `createConfig()`, presets, plugin replacement, and environment variables. |
79
+ | [Migration](./docs/migration.md) | Moving a project from a hand-written flat config to this package. |
80
+ | [Contributing](./CONTRIBUTING.md) | Local development workflow and pull request expectations. |
81
+ | [Maintainer guide](./docs/maintainer-guide.md) | Rule, preset, dependency, and release maintenance. |
82
+ | [Support](./SUPPORT.md) | Issue triage and reproduction details. |
83
+ | [Security](./SECURITY.md) | Private vulnerability reporting. |
84
+ | [Code of conduct](./CODE_OF_CONDUCT.md) | Participation standards for the project. |
85
85
 
86
86
  ## `createConfig()`
87
87
 
@@ -93,23 +93,23 @@ shared defaults:
93
93
  import { createConfig } from "eslint-config-nick2bad4u";
94
94
 
95
95
  export default createConfig({
96
- allowDefaultProjectFilePatterns: [
97
- "*.config.{js,mjs,cjs,ts,mts,cts}",
98
- "*.config.*.{js,mjs,cjs,ts,mts,cts}",
99
- ".*rc.{js,mjs,cjs,ts,mts,cts}",
100
- "preset.mjs",
101
- ],
102
- rootDirectory: import.meta.dirname,
103
- tsconfigPaths: ["./tsconfig.eslint.json"],
96
+ allowDefaultProjectFilePatterns: [
97
+ "*.config.{js,mjs,cjs,ts,mts,cts}",
98
+ "*.config.*.{js,mjs,cjs,ts,mts,cts}",
99
+ ".*rc.{js,mjs,cjs,ts,mts,cts}",
100
+ "preset.mjs",
101
+ ],
102
+ rootDirectory: import.meta.dirname,
103
+ tsconfigPaths: ["./tsconfig.eslint.json"],
104
104
  });
105
105
  ```
106
106
 
107
- | Option | Type | Default | Use it when |
108
- | --- | --- | --- | --- |
109
- | `allowDefaultProjectFilePatterns` | `readonly string[]` | `["*.mjs", ".*.mjs"]` | Root config files are intentionally outside `tsconfigPaths`; do not include files already covered by your lint tsconfig. |
110
- | `rootDirectory` | `string` | `process.cwd()` | ESLint runs outside the project root or a monorepo package needs its own root. |
111
- | `tsconfigPaths` | `readonly string[]` | `["./tsconfig.eslint.json"]` | The project uses a differently named lint tsconfig or a truly separate TypeScript project. |
112
- | `plugins` | `Readonly<Record<string, unknown>>` | `{}` | You need to dogfood a local plugin build or disable packaged plugin rules by namespace. |
107
+ | Option | Type | Default | Use it when |
108
+ | --------------------------------- | ----------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
109
+ | `allowDefaultProjectFilePatterns` | `readonly string[]` | `["*.mjs", ".*.mjs"]` | Root config files are intentionally outside `tsconfigPaths`; do not include files already covered by your lint tsconfig. |
110
+ | `rootDirectory` | `string` | `process.cwd()` | ESLint runs outside the project root or a monorepo package needs its own root. |
111
+ | `tsconfigPaths` | `readonly string[]` | `["./tsconfig.eslint.json"]` | The project uses a differently named lint tsconfig or a truly separate TypeScript project. |
112
+ | `plugins` | `Readonly<Record<string, unknown>>` | `{}` | You need to dogfood a local plugin build or disable packaged plugin rules by namespace. |
113
113
 
114
114
  An example copy-paste config is available at
115
115
  [`examples/eslint.config.create.mjs`](./examples/eslint.config.create.mjs).
@@ -121,30 +121,30 @@ Detailed configuration examples live in the
121
121
  All presets are available from the default export as `nick2bad4u.configs.*` and
122
122
  from the named `presets` export.
123
123
 
124
- | Preset | Purpose |
125
- | --- | --- |
126
- | `all` | Full shared config, including packaged Typefest and Etc-Misc source-rule sections. |
127
- | `recommended` | Alias for `all`; provided for familiar preset naming. |
128
- | `base` | Shared config without explicit source-rule plugin sections. |
129
- | `withoutCopilot` | Full shared config without Copilot rules. |
130
- | `withoutDocusaurus2` | Full shared config without Docusaurus 2 plugin rules. |
131
- | `withoutEtcMisc` | Full shared config without the Etc-Misc source-rule section. |
132
- | `withoutFileProgress2` | Full shared config without File Progress 2 rules. |
133
- | `withoutGitHubActions2` | Full shared config without GitHub Actions 2 rules. |
134
- | `withoutGithubActions2` | Deprecated alias for `withoutGitHubActions2`. |
135
- | `withoutImmutable2` | Full shared config without Immutable 2 rules. |
136
- | `withoutRemark` | Full shared config without Remark plugin rules. |
137
- | `withoutRepo` | Full shared config without Repo plugin rules. |
138
- | `withoutRuntimeCleanup` | Full shared config without Runtime Cleanup plugin rules. |
139
- | `withoutSdl2` | Full shared config without SDL 2 rules. |
140
- | `withoutStylelint2` | Full shared config without Stylelint 2 rules. |
141
- | `withoutTestSignal` | Full shared config without Test Signal plugin rules. |
142
- | `withoutTsconfig` | Full shared config without tsconfig-validation rules. |
143
- | `withoutTsdocRequire2` | Full shared config without TSDoc Require 2 rules. |
144
- | `withoutTypedoc` | Full shared config without TypeDoc rules. |
145
- | `withoutTypefest` | Full shared config without the Typefest source-rule section. |
146
- | `withoutVite` | Full shared config without Vite plugin rules. |
147
- | `withoutWriteGoodComments2` | Full shared config without Write Good Comments 2 rules. |
124
+ | Preset | Purpose |
125
+ | --------------------------- | ---------------------------------------------------------------------------------- |
126
+ | `all` | Full shared config, including packaged Typefest and Etc-Misc source-rule sections. |
127
+ | `recommended` | Alias for `all`; provided for familiar preset naming. |
128
+ | `base` | Shared config without explicit source-rule plugin sections. |
129
+ | `withoutCopilot` | Full shared config without Copilot rules. |
130
+ | `withoutDocusaurus2` | Full shared config without Docusaurus 2 plugin rules. |
131
+ | `withoutEtcMisc` | Full shared config without the Etc-Misc source-rule section. |
132
+ | `withoutFileProgress2` | Full shared config without File Progress 2 rules. |
133
+ | `withoutGitHubActions2` | Full shared config without GitHub Actions 2 rules. |
134
+ | `withoutGithubActions2` | Deprecated alias for `withoutGitHubActions2`. |
135
+ | `withoutImmutable2` | Full shared config without Immutable 2 rules. |
136
+ | `withoutRemark` | Full shared config without Remark plugin rules. |
137
+ | `withoutRepo` | Full shared config without Repo plugin rules. |
138
+ | `withoutRuntimeCleanup` | Full shared config without Runtime Cleanup plugin rules. |
139
+ | `withoutSdl2` | Full shared config without SDL 2 rules. |
140
+ | `withoutStylelint2` | Full shared config without Stylelint 2 rules. |
141
+ | `withoutTestSignal` | Full shared config without Test Signal plugin rules. |
142
+ | `withoutTsconfig` | Full shared config without tsconfig-validation rules. |
143
+ | `withoutTsdocRequire2` | Full shared config without TSDoc Require 2 rules. |
144
+ | `withoutTypedoc` | Full shared config without TypeDoc rules. |
145
+ | `withoutTypefest` | Full shared config without the Typefest source-rule section. |
146
+ | `withoutVite` | Full shared config without Vite plugin rules. |
147
+ | `withoutWriteGoodComments2` | Full shared config without Write Good Comments 2 rules. |
148
148
 
149
149
  Use a `without*` preset when a repository does not use that surface or when it
150
150
  needs to provide a local build of that plugin for dogfooding.
@@ -157,15 +157,15 @@ can lint: source, tests, scripts, dotfiles, examples, and docs tooling.
157
157
 
158
158
  ```json
159
159
  {
160
- "$schema": "https://www.schemastore.org/tsconfig.json",
161
- "extends": "./tsconfig.json",
162
- "compilerOptions": {
163
- "allowJs": true,
164
- "checkJs": true,
165
- "noEmit": true
166
- },
167
- "exclude": ["node_modules/**", "dist/**", "coverage/**", ".cache/**"],
168
- "include": ["**/*", "**/.*"]
160
+ "$schema": "https://www.schemastore.org/tsconfig.json",
161
+ "extends": "./tsconfig.json",
162
+ "compilerOptions": {
163
+ "allowJs": true,
164
+ "checkJs": true,
165
+ "noEmit": true
166
+ },
167
+ "exclude": ["node_modules/**", "dist/**", "coverage/**", ".cache/**"],
168
+ "include": ["**/*", "**/.*"]
169
169
  }
170
170
  ```
171
171
 
@@ -187,17 +187,17 @@ import nick2bad4u from "eslint-config-nick2bad4u";
187
187
  import localTypefest from "./plugin.mjs";
188
188
 
189
189
  export default [
190
- ...nick2bad4u.configs.withoutTypefest,
191
- {
192
- files: ["src/**/*.{ts,tsx,mts,cts}"],
193
- name: "Local Typefest rules",
194
- plugins: {
195
- typefest: localTypefest,
196
- },
197
- rules: {
198
- ...localTypefest.configs.experimental.rules,
199
- },
200
- },
190
+ ...nick2bad4u.configs.withoutTypefest,
191
+ {
192
+ files: ["src/**/*.{ts,tsx,mts,cts}"],
193
+ name: "Local Typefest rules",
194
+ plugins: {
195
+ typefest: localTypefest,
196
+ },
197
+ rules: {
198
+ ...localTypefest.configs.experimental.rules,
199
+ },
200
+ },
201
201
  ];
202
202
  ```
203
203
 
@@ -209,9 +209,9 @@ Use the same shape for other plugin namespaces, such as `withoutCopilot`,
209
209
  ### JSON schema validation
210
210
 
211
211
  Schema validation is disabled by default because schema fetching can make lint
212
- runs flaky in offline or locked-down environments. To opt in, install an
213
- ESLint-10-compatible `eslint-plugin-json-schema-validator` in the consuming repo
214
- and set the opt-in environment variable when running ESLint:
212
+ runs flaky in offline or locked-down environments. To opt in, install
213
+ `eslint-plugin-json-schema-validator-2` in the consuming repo and set the opt-in
214
+ environment variable when running ESLint:
215
215
 
216
216
  ```sh
217
217
  ENABLE_JSON_SCHEMA_VALIDATION=1 eslint .
@@ -222,11 +222,11 @@ ENABLE_JSON_SCHEMA_VALIDATION=1 eslint .
222
222
  `eslint-plugin-file-progress-2` is enabled by default. Control it with
223
223
  `ESLINT_PROGRESS`:
224
224
 
225
- | Value | Behavior |
226
- | --- | --- |
227
- | unset or `on` | Show progress and file names. |
228
- | `nofile` | Show progress without file names. |
229
- | `off`, `0`, or `false` | Disable progress output. |
225
+ | Value | Behavior |
226
+ | ---------------------- | --------------------------------- |
227
+ | unset or `on` | Show progress and file names. |
228
+ | `nofile` | Show progress without file names. |
229
+ | `off`, `0`, or `false` | Disable progress output. |
230
230
 
231
231
  ## Development checks
232
232
 
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair -- Disabled by design */
2
- /* eslint-disable import-x/no-rename-default, no-console, @typescript-eslint/triple-slash-reference, import-x/max-dependencies -- Disabled by design */
2
+ /* eslint-disable import-x/no-rename-default, @typescript-eslint/triple-slash-reference, import-x/max-dependencies -- Disabled by design */
3
3
  /**
4
4
  * Optimized ESLint configuration
5
5
  *
@@ -38,6 +38,7 @@ import githubActions from "eslint-plugin-github-actions-2";
38
38
  import immutable from "eslint-plugin-immutable-2";
39
39
  import { importX } from "eslint-plugin-import-x";
40
40
  import jsdoc from "eslint-plugin-jsdoc";
41
+ import jsonSchemaValidator from "eslint-plugin-json-schema-validator-2";
41
42
  import jsonc from "eslint-plugin-jsonc";
42
43
  import listeners from "eslint-plugin-listeners";
43
44
  import math from "eslint-plugin-math";
@@ -74,55 +75,36 @@ import writeGoodComments from "eslint-plugin-write-good-comments-2";
74
75
  import yml from "eslint-plugin-yml";
75
76
  import globals from "globals";
76
77
  import * as jsoncEslintParser from "jsonc-eslint-parser";
77
- import { createRequire } from "node:module";
78
78
  import * as path from "node:path";
79
79
  import * as tomlEslintParser from "toml-eslint-parser";
80
80
  import { arrayFirst, arrayJoin, isDefined, isPresent, keyIn, objectEntries, objectFromEntries, objectHasOwn, objectKeys, setHas, stringSplit, } from "ts-extras";
81
81
  import tseslint from "typescript-eslint";
82
82
  import * as yamlEslintParser from "yaml-eslint-parser";
83
- const require = createRequire(import.meta.url);
84
83
  const processEnvironment = globalThis.process.env;
85
84
  // #region ✅ JSON Schema Validator
86
85
  // ═══════════════════════════════════════════════════════════════════════════════
87
- // NOTE: eslint-plugin-json-schema-validator validates more than JSON files. Its
86
+ // NOTE: eslint-plugin-json-schema-validator-2 validates more than JSON files. Its
88
87
  // recommended preset also covers JSONC, JSON5, YAML, TOML, JavaScript, and Vue
89
88
  // custom blocks. Keep the whole preset opt-in so default linting remains
90
- // offline-friendly and compatible with ESLint 10 while the validator catches up.
89
+ // offline-friendly.
90
+ // PowerShell one-shot:
91
+ // $env:ENABLE_JSON_SCHEMA_VALIDATION=1; npx eslint .; Remove-Item Env:ENABLE_JSON_SCHEMA_VALIDATION -EA 0
91
92
  const enableJsonSchemaValidation = processEnvironment["ENABLE_JSON_SCHEMA_VALIDATION"] === "1";
92
- const jsonSchemaValidatorPackageName = "eslint-plugin-json-schema-validator";
93
- const jsonSchemaValidatorRecommendedConfigName = "recommended";
94
- const jsonSchemaValidatorRuleName = "no-invalid";
95
- let jsonSchemaValidatorRecommendedConfigs = [];
96
- if (enableJsonSchemaValidation) {
97
- try {
98
- // eslint-disable-next-line import-x/no-dynamic-require -- Controlled optional package name constant; no user input reaches require.
99
- const loadedJsonSchemaValidator = require(jsonSchemaValidatorPackageName);
100
- const jsonSchemaValidatorCandidate = objectHasOwn(loadedJsonSchemaValidator, "default")
101
- ? loadedJsonSchemaValidator.default
102
- : loadedJsonSchemaValidator;
103
- if (hasPluginRule(jsonSchemaValidatorCandidate, jsonSchemaValidatorRuleName)) {
104
- const recommendedConfigs = getNamedPluginConfigs(jsonSchemaValidatorCandidate, jsonSchemaValidatorRecommendedConfigName, "✅ JSON Schema Validator: Recommended");
105
- if (recommendedConfigs === null) {
106
- console.warn(`[eslint-config-nick2bad4u] ${jsonSchemaValidatorPackageName} did not export configs.${jsonSchemaValidatorRecommendedConfigName}; JSON schema validation remains disabled.`);
107
- }
108
- else {
109
- jsonSchemaValidatorRecommendedConfigs = recommendedConfigs;
110
- }
111
- }
112
- else {
113
- console.warn(`[eslint-config-nick2bad4u] ${jsonSchemaValidatorPackageName} did not export a plugin with the ${jsonSchemaValidatorRuleName} rule; JSON schema validation remains disabled.`);
114
- }
115
- }
116
- catch {
117
- console.warn(`[eslint-config-nick2bad4u] ${jsonSchemaValidatorPackageName} is not installed; JSON schema validation remains disabled.`);
118
- }
119
- }
93
+ const jsonSchemaValidatorRecommendedConfigs = enableJsonSchemaValidation
94
+ ? jsonSchemaValidator.configs.recommended.map((config, index) => ({
95
+ ...config,
96
+ name: config.name ??
97
+ `✅ JSON Schema Validator: Recommended ${String(index + 1)}`,
98
+ }))
99
+ : [];
120
100
  // #endregion ✅ JSON Schema Validator
121
101
  // #region 📁 Markdown Code Block Processor
122
102
  // ═══════════════════════════════════════════════════════════════════════════════
123
103
  // The markdown processor changes Markdown linting from "lint the document" to
124
104
  // "lint extracted fenced code blocks". Keep it opt-in so remark/remark and the
125
105
  // markdown/gfm document rules remain the default Markdown path.
106
+ // PowerShell one-shot:
107
+ // $flag = "ENABLE_MARKDOWN_CODE_BLOCK_LINTING"; Set-Item "Env:$flag" 1; npx eslint .; Remove-Item "Env:$flag" -EA 0
126
108
  const enableMarkdownCodeBlockLinting = processEnvironment["ENABLE_MARKDOWN_CODE_BLOCK_LINTING"] === "1";
127
109
  // #endregion 📁 Markdown Code Block Processor
128
110
  // #region 🏗️ Setup and Public Types
@@ -197,6 +179,9 @@ const TYPEDOC_API_IGNORES = Object.freeze([
197
179
  * - "nofile": enable progress but hide file names
198
180
  * - "off" / "0" / "false": disable progress
199
181
  */
182
+ // PowerShell one-shots:
183
+ // $env:ESLINT_PROGRESS="nofile"; npx eslint .; Remove-Item Env:ESLINT_PROGRESS -EA 0
184
+ // $env:ESLINT_PROGRESS="off"; npx eslint .; Remove-Item Env:ESLINT_PROGRESS -EA 0
200
185
  const ESLINT_PROGRESS_MODE = (processEnvironment["ESLINT_PROGRESS"] ?? "on").toLowerCase();
201
186
  const CI_ENVIRONMENT_VALUE = (processEnvironment["CI"] ?? "").toLowerCase();
202
187
  const IS_CI = CI_ENVIRONMENT_VALUE !== "" &&
@@ -943,7 +928,7 @@ export const createConfig = (options = {}) => {
943
928
  specialCharacters: "keep",
944
929
  type: "natural",
945
930
  useConfigurationIf: {
946
- matchesAstSelector: "TSAsExpression > ArrayExpression",
931
+ matchesAstSelector: "TSAsExpression:not(TSSatisfiesExpression > TSAsExpression) > ArrayExpression",
947
932
  },
948
933
  },
949
934
  ],
@@ -1009,6 +994,9 @@ export const createConfig = (options = {}) => {
1009
994
  // prettier-ignore
1010
995
  rules: {
1011
996
  ...repo.configs.recommended.rules,
997
+ ...repo.configs.github.rules,
998
+ ...repo.configs.dependabot.rules,
999
+ ...repo.configs.node.rules,
1012
1000
  "repo-compliance/require-aws-amplify-artifacts-base-directory": "off",
1013
1001
  "repo-compliance/require-aws-amplify-artifacts-base-directory-relative-path": "off",
1014
1002
  "repo-compliance/require-aws-amplify-artifacts-files": "off",
@@ -1033,7 +1021,7 @@ export const createConfig = (options = {}) => {
1033
1021
  "repo-compliance/require-bitbucket-pipelines-pull-requests": "off",
1034
1022
  "repo-compliance/require-bitbucket-pipelines-pull-requests-target-branches": "off",
1035
1023
  "repo-compliance/require-bitbucket-pipelines-step-name": "off",
1036
- "repo-compliance/require-copilot-instructions-file": "warn",
1024
+ "repo-compliance/require-copilot-instructions-file": "off",
1037
1025
  "repo-compliance/require-digitalocean-app-spec-component": "off",
1038
1026
  "repo-compliance/require-digitalocean-app-spec-file": "off",
1039
1027
  "repo-compliance/require-digitalocean-app-spec-name": "off",
@@ -1098,9 +1086,6 @@ export const createConfig = (options = {}) => {
1098
1086
  "repo-compliance/require-vercel-version-value": "off",
1099
1087
  },
1100
1088
  },
1101
- repo.configs.github,
1102
- repo.configs.dependabot,
1103
- repo.configs.node,
1104
1089
  {
1105
1090
  ...typedoc.configs.recommended,
1106
1091
  files: [...TYPEDOC_API_FILE_PATTERNS],
@@ -3357,43 +3342,12 @@ function flattenConfigs(configs) {
3357
3342
  return result;
3358
3343
  }, []);
3359
3344
  }
3360
- function getNamedPluginConfigs(pluginCandidate, configName, fallbackName) {
3361
- const { configs } = pluginCandidate;
3362
- if (typeof configs !== "object" ||
3363
- !isPresent(configs) ||
3364
- Array.isArray(configs) ||
3365
- !objectHasOwn(configs, configName)) {
3366
- return null;
3367
- }
3368
- const configInput = configs[configName];
3369
- const normalizedConfigs = flattenConfigs([configInput]);
3370
- return normalizedConfigs.map((config, index) => ({
3371
- ...config,
3372
- name: config.name ??
3373
- (normalizedConfigs.length === 1
3374
- ? fallbackName
3375
- : `${fallbackName} ${String(index + 1)}`),
3376
- }));
3377
- }
3378
3345
  function getRulePluginName(ruleName) {
3379
3346
  if (ruleName.startsWith("@")) {
3380
3347
  return arrayJoin(stringSplit(ruleName, "/").slice(0, 2), "/");
3381
3348
  }
3382
3349
  return arrayFirst(stringSplit(ruleName, "/")) ?? ruleName;
3383
3350
  }
3384
- function hasPluginRule(pluginCandidate, ruleName) {
3385
- if (typeof pluginCandidate !== "object" ||
3386
- !isPresent(pluginCandidate) ||
3387
- Array.isArray(pluginCandidate) ||
3388
- !objectHasOwn(pluginCandidate, "rules")) {
3389
- return false;
3390
- }
3391
- const { rules } = pluginCandidate;
3392
- return (typeof rules === "object" &&
3393
- isPresent(rules) &&
3394
- !Array.isArray(rules) &&
3395
- objectHasOwn(rules, ruleName));
3396
- }
3397
3351
  function removeDisabledPluginRules(configs, disabledPluginNames) {
3398
3352
  if (disabledPluginNames.size === 0) {
3399
3353
  return [...configs];