@fabdeh/eslint-config 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +310 -69
- package/dist/index.d.mts +15161 -13266
- package/dist/index.mjs +611 -408
- package/package.json +26 -37
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,60 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join, normalize, resolve } from "node:path";
|
|
4
3
|
import process from "node:process";
|
|
4
|
+
import { globSync } from "glob";
|
|
5
5
|
import { isPackageExists } from "local-pkg";
|
|
6
6
|
import eslintComments from "@eslint-community/eslint-plugin-eslint-comments";
|
|
7
7
|
import * as importX from "eslint-plugin-import-x";
|
|
8
8
|
import preferArrowFunctions from "eslint-plugin-prefer-arrow-functions";
|
|
9
9
|
import unusedImports from "eslint-plugin-unused-imports";
|
|
10
10
|
import globals from "globals";
|
|
11
|
+
import tseslint from "typescript-eslint";
|
|
11
12
|
import jsdocPlugin from "eslint-plugin-jsdoc";
|
|
12
13
|
import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
|
|
13
14
|
import nodePlugin from "eslint-plugin-n";
|
|
14
15
|
import perfectionistPlugin from "eslint-plugin-perfectionist";
|
|
16
|
+
import { readFile } from "node:fs/promises";
|
|
17
|
+
import { findUp, findUpSync } from "find-up-simple";
|
|
15
18
|
import { configs } from "eslint-plugin-regexp";
|
|
16
19
|
import unicornPlugin from "eslint-plugin-unicorn";
|
|
20
|
+
import { FlatConfigComposer } from "eslint-flat-config-utils";
|
|
21
|
+
//#region src/config-presets.ts
|
|
22
|
+
const CONFIG_PRESET_FULL_ON = {
|
|
23
|
+
angular: true,
|
|
24
|
+
gitignore: true,
|
|
25
|
+
jsdoc: true,
|
|
26
|
+
jsonc: true,
|
|
27
|
+
markdown: true,
|
|
28
|
+
ngrx: true,
|
|
29
|
+
playwright: true,
|
|
30
|
+
pnpm: true,
|
|
31
|
+
regexp: true,
|
|
32
|
+
stylistic: { experimental: true },
|
|
33
|
+
tailwindcss: true,
|
|
34
|
+
toml: true,
|
|
35
|
+
typescript: { enableErasableSyntaxOnly: true },
|
|
36
|
+
unicorn: true,
|
|
37
|
+
vitest: true,
|
|
38
|
+
yaml: true
|
|
39
|
+
};
|
|
40
|
+
const CONFIG_PRESET_FULL_OFF = {
|
|
41
|
+
angular: false,
|
|
42
|
+
gitignore: false,
|
|
43
|
+
jsdoc: false,
|
|
44
|
+
jsonc: false,
|
|
45
|
+
markdown: false,
|
|
46
|
+
ngrx: false,
|
|
47
|
+
playwright: false,
|
|
48
|
+
pnpm: false,
|
|
49
|
+
regexp: false,
|
|
50
|
+
stylistic: false,
|
|
51
|
+
tailwindcss: false,
|
|
52
|
+
toml: false,
|
|
53
|
+
typescript: false,
|
|
54
|
+
unicorn: false,
|
|
55
|
+
vitest: false,
|
|
56
|
+
yaml: false
|
|
57
|
+
};
|
|
17
58
|
/**
|
|
18
59
|
* A glob pattern that matches JavaScript and TypeScript source files (including JSX/TSX).
|
|
19
60
|
*/
|
|
@@ -31,22 +72,6 @@ const GLOB_TS_EXT = "?([cm])ts?(x)";
|
|
|
31
72
|
*/
|
|
32
73
|
const GLOB_TS = `**/*.${GLOB_TS_EXT}`;
|
|
33
74
|
/**
|
|
34
|
-
* A glob pattern that matches all CSS files.
|
|
35
|
-
*/
|
|
36
|
-
const GLOB_CSS = "**/*.css";
|
|
37
|
-
/**
|
|
38
|
-
* A glob pattern that matches all PostCSS files.
|
|
39
|
-
*/
|
|
40
|
-
const GLOB_POSTCSS = "**/*.{p,post}css";
|
|
41
|
-
/**
|
|
42
|
-
* A glob pattern that matches all LESS files.
|
|
43
|
-
*/
|
|
44
|
-
const GLOB_LESS = "**/*.less";
|
|
45
|
-
/**
|
|
46
|
-
* A glob pattern that matches all SCSS files.
|
|
47
|
-
*/
|
|
48
|
-
const GLOB_SCSS = "**/*.scss";
|
|
49
|
-
/**
|
|
50
75
|
* A glob pattern that matches all JSON files.
|
|
51
76
|
*/
|
|
52
77
|
const GLOB_JSON = "**/*.json";
|
|
@@ -79,29 +104,14 @@ const GLOB_YAML = "**/*.y?(a)ml";
|
|
|
79
104
|
*/
|
|
80
105
|
const GLOB_TOML = "**/*.toml";
|
|
81
106
|
/**
|
|
82
|
-
* A glob pattern that matches XML files.
|
|
83
|
-
*/
|
|
84
|
-
const GLOB_XML = "**/*.xml";
|
|
85
|
-
/**
|
|
86
|
-
* A glob pattern that matches SVG files.
|
|
87
|
-
*/
|
|
88
|
-
const GLOB_SVG = "**/*.svg";
|
|
89
|
-
/**
|
|
90
|
-
* A glob pattern that matches GraphQL files.
|
|
91
|
-
*/
|
|
92
|
-
const GLOB_GRAPHQL = "**/*.{g,graph}ql";
|
|
93
|
-
/**
|
|
94
107
|
* A glob pattern that matches HTML files.
|
|
95
108
|
*/
|
|
96
109
|
const GLOB_HTML = "**/*.htm?(l)";
|
|
97
110
|
/**
|
|
98
111
|
* A glob pattern that matches test files.
|
|
99
112
|
*/
|
|
100
|
-
const GLOB_TESTS = [
|
|
101
|
-
|
|
102
|
-
`**/*.test.?([cm])[jt]s`,
|
|
103
|
-
`**/test-setup.?([cm])[jt]s`
|
|
104
|
-
];
|
|
113
|
+
const GLOB_TESTS = [`**/*.spec.?([cm])[jt]s`, `**/*.test.?([cm])[jt]s`];
|
|
114
|
+
const GLOB_VITEST = [...GLOB_TESTS, `**/test-setup.?([cm])[jt]s`];
|
|
105
115
|
/**
|
|
106
116
|
* A glob pattern that matches files to exclude from linting.
|
|
107
117
|
*/
|
|
@@ -111,7 +121,7 @@ const GLOB_EXCLUDE = [
|
|
|
111
121
|
"**/package-lock.json",
|
|
112
122
|
"**/yarn.lock",
|
|
113
123
|
"**/pnpm-lock.yaml",
|
|
114
|
-
"**/bun.
|
|
124
|
+
"**/bun.lock?(b)",
|
|
115
125
|
"**/output",
|
|
116
126
|
"**/coverage",
|
|
117
127
|
"**/temp",
|
|
@@ -137,8 +147,7 @@ const GLOB_EXCLUDE = [
|
|
|
137
147
|
"**/LICENSE*",
|
|
138
148
|
"**/__snapshots__",
|
|
139
149
|
"**/auto-import?(s).d.ts",
|
|
140
|
-
"**/components.d.ts"
|
|
141
|
-
"**/prettier-types.ts"
|
|
150
|
+
"**/components.d.ts"
|
|
142
151
|
];
|
|
143
152
|
//#endregion
|
|
144
153
|
//#region src/shared/utils.ts
|
|
@@ -172,6 +181,19 @@ function fileExists(path) {
|
|
|
172
181
|
}
|
|
173
182
|
}
|
|
174
183
|
/**
|
|
184
|
+
* Checks whether the given path points to an existing directory.
|
|
185
|
+
*
|
|
186
|
+
* @param path - Filesystem path to validate.
|
|
187
|
+
* @returns `true` when the path exists and is a directory; otherwise `false`.
|
|
188
|
+
*/
|
|
189
|
+
function isDirectory(path) {
|
|
190
|
+
try {
|
|
191
|
+
return statSync(path).isDirectory();
|
|
192
|
+
} catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
175
197
|
* Retrieves the root directory of the workspace.
|
|
176
198
|
*
|
|
177
199
|
* This function determines the root directory of the workspace by checking for specific files
|
|
@@ -184,7 +206,7 @@ function fileExists(path) {
|
|
|
184
206
|
* @returns The root directory of the workspace.
|
|
185
207
|
*/
|
|
186
208
|
function getWorkspaceRoot(dir, candidateRoot) {
|
|
187
|
-
if (process.env
|
|
209
|
+
if (process.env["NX_WORKSPACE_ROOT"]) return process.env["NX_WORKSPACE_ROOT"];
|
|
188
210
|
if (dirname(dir) === dir) return candidateRoot;
|
|
189
211
|
if ([
|
|
190
212
|
join(dir, "nx.json"),
|
|
@@ -228,15 +250,41 @@ function isPackageInScope(name) {
|
|
|
228
250
|
* @returns A promise that resolves when the operation is complete.
|
|
229
251
|
*/
|
|
230
252
|
async function ensurePackages(packages) {
|
|
231
|
-
if (process.env
|
|
253
|
+
if (process.env["CI"] || !process.stdout.isTTY || !IS_CWD_IN_SCOPE) return;
|
|
232
254
|
const nonExistingPackages = packages.filter((i) => i && !isPackageInScope(i));
|
|
233
255
|
if (nonExistingPackages.length === 0) return;
|
|
234
256
|
if (await (await import("@clack/prompts")).confirm({ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?` })) await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
|
|
235
257
|
}
|
|
236
258
|
/**
|
|
259
|
+
* Detects whether the current process is running in an interactive editor environment.
|
|
260
|
+
*
|
|
261
|
+
* The check returns `false` in CI and Git hook\/`lint-staged` contexts to avoid
|
|
262
|
+
* editor-specific behavior in non-interactive executions.
|
|
263
|
+
*
|
|
264
|
+
* Editor detection is based on common environment variables from VS Code,
|
|
265
|
+
* JetBrains IDEs, Vim\/Neovim, and Zed.
|
|
266
|
+
*
|
|
267
|
+
* @returns `true` when execution appears to be inside a supported editor; otherwise `false`.
|
|
268
|
+
*/
|
|
269
|
+
function isInEditorEnv() {
|
|
270
|
+
if (process.env["CI"]) return false;
|
|
271
|
+
if (isInGitHooksOrLintStaged()) return false;
|
|
272
|
+
return !!(process.env["VSCODE_PID"] || process.env["VSCODE_CWD"] || process.env["JETBRAINS_IDE"] || process.env["VIM"] || process.env["NVIM"] || process.env["ZED_ENVIRONMENT"] && !process.env["ZED_TERM"]);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Detects whether the current process is running from a Git hook or `lint\-staged`.
|
|
276
|
+
*
|
|
277
|
+
* It checks common environment variables set by Git tooling and npm lifecycle scripts.
|
|
278
|
+
*
|
|
279
|
+
* @returns `true` when execution appears to be in a Git hook or `lint\-staged` context.
|
|
280
|
+
*/
|
|
281
|
+
function isInGitHooksOrLintStaged() {
|
|
282
|
+
return !!(process.env["GIT_PARAMS"] || process.env["VSCODE_GIT_COMMAND"] || process.env["npm_lifecycle_script"]?.startsWith("lint-staged") || process.env["npm_lifecycle_script"]?.startsWith("nano-staged"));
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
237
285
|
* Returns the object representation of the configuration or an empty object if it is a boolean.
|
|
238
286
|
*
|
|
239
|
-
* @param options - The {@link
|
|
287
|
+
* @param options - The {@link DefineConfigOptions} object to extract the sub-options from.
|
|
240
288
|
* @param key - The property name.
|
|
241
289
|
* @returns An object representing the required options.
|
|
242
290
|
*/
|
|
@@ -245,6 +293,67 @@ function resolveSubOptions(options, key) {
|
|
|
245
293
|
if (typeof option === "boolean") return {};
|
|
246
294
|
return option ?? {};
|
|
247
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Replace Windows with posix style paths
|
|
298
|
+
*
|
|
299
|
+
* @param filePath - Path to convert
|
|
300
|
+
* @returns Converted filepath
|
|
301
|
+
*/
|
|
302
|
+
function convertPathToPosix(filePath) {
|
|
303
|
+
return normalize(filePath).replaceAll("\\", "/");
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Checks if a provided path is a directory and returns a glob string matching
|
|
307
|
+
* all files under that directory if so, the path itself otherwise.
|
|
308
|
+
*
|
|
309
|
+
* Reason for this is that `glob` needs `/**` to collect all the files under a
|
|
310
|
+
* directory where as our previous implementation without `glob` simply walked
|
|
311
|
+
* a directory that is passed. So this is to maintain backwards compatibility.
|
|
312
|
+
*
|
|
313
|
+
* Also makes sure all path separators are POSIX style for `glob` compatibility.
|
|
314
|
+
*
|
|
315
|
+
* @param [options] - An options object
|
|
316
|
+
* @param [options.extensions] - An array of accepted extensions
|
|
317
|
+
* @param [options.cwd] - The cwd to use to resolve relative pathnames
|
|
318
|
+
* @returns A function that takes a pathname and returns a glob that
|
|
319
|
+
* matches all files with the provided extensions if
|
|
320
|
+
* pathname is a directory.
|
|
321
|
+
*/
|
|
322
|
+
function pathToGlobPattern(options) {
|
|
323
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
324
|
+
const extensions = options?.extensions?.map((ext) => ext.replace(/^\./, "")) ?? [];
|
|
325
|
+
const suffix = extensions.length === 0 ? "/**/*" : extensions.length === 1 ? `/**/*.${extensions[0]}` : `/**/*.{${extensions.join(",")}}`;
|
|
326
|
+
return (path) => {
|
|
327
|
+
let newPath = path;
|
|
328
|
+
if (isDirectory(resolve(cwd, path))) newPath = path.replace(/[/\\]$/, "") + suffix;
|
|
329
|
+
return convertPathToPosix(newPath);
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Finds the first valid Playwright test directory declared via `testDir` in any
|
|
334
|
+
* `playwright.config.ts` file under the current workspace.
|
|
335
|
+
*
|
|
336
|
+
* The function:
|
|
337
|
+
* - Locates Playwright config files, excluding `node_modules`.
|
|
338
|
+
* - Reads each config as text.
|
|
339
|
+
* - Extracts `testDir` with a regex.
|
|
340
|
+
* - Resolves `testDir` relative to the config file location.
|
|
341
|
+
* - Returns the first resolved path that exists as a directory.
|
|
342
|
+
*
|
|
343
|
+
* @returns Absolute path to the first existing Playwright test directory, or `undefined` if none is found.
|
|
344
|
+
*/
|
|
345
|
+
function getPlaywrightDirectory() {
|
|
346
|
+
const playwrightConfigs = globSync("**/playwright.config.ts", { ignore: ["**/node_modules/**"] });
|
|
347
|
+
for (const config of playwrightConfigs) try {
|
|
348
|
+
const configContent = readFileSync(config, "utf-8");
|
|
349
|
+
const match = /testDir:\s*["'](.+)["'],?/.exec(configContent);
|
|
350
|
+
if (match) {
|
|
351
|
+
const testDir = match[1];
|
|
352
|
+
const resolvedTestDir = resolve(dirname(config), testDir);
|
|
353
|
+
if (isDirectory(resolvedTestDir)) return resolvedTestDir;
|
|
354
|
+
}
|
|
355
|
+
} catch {}
|
|
356
|
+
}
|
|
248
357
|
//#endregion
|
|
249
358
|
//#region src/configs/angular.ts
|
|
250
359
|
/**
|
|
@@ -252,15 +361,17 @@ function resolveSubOptions(options, key) {
|
|
|
252
361
|
*
|
|
253
362
|
* @param options - Configuration options for Angular ESLint.
|
|
254
363
|
* @param options.enableAccessibilityRules - Whether to enable accessibility rules for HTML templates.
|
|
255
|
-
* @param options.tsOverrides - Additional TypeScript rule overrides.
|
|
256
|
-
* @param options.htmlOverrides - Additional HTML rule overrides.
|
|
257
364
|
* @param options.prefix - The prefix to use for Angular component and directive selectors.
|
|
258
365
|
* @returns A promise that resolves to an array of ESLint configurations.
|
|
259
366
|
*/
|
|
260
367
|
async function angular(options = {}) {
|
|
261
368
|
const angularEslint = await interopDefault(import("angular-eslint"));
|
|
262
|
-
const { enableAccessibilityRules = true,
|
|
263
|
-
|
|
369
|
+
const { enableAccessibilityRules = true, overrides = {}, prefix = "app", ignoreClassNamePatternForInjectableProvidedIn: ignoreClassNamePattern, componentStylesMode = "string", preferOnPushOnly = true, banExperimentalApi = true, banDeveloperPreviewApi = true, inlineTemplateAndStyles = false } = options;
|
|
370
|
+
const tsOverrides = {};
|
|
371
|
+
const htmlOverrides = {};
|
|
372
|
+
for (const [key, value] of Object.entries(overrides)) if (key.startsWith("@angular-eslint/template/")) htmlOverrides[key] = value;
|
|
373
|
+
else if (key.startsWith("@angular-eslint/")) tsOverrides[key] = value;
|
|
374
|
+
return [{
|
|
264
375
|
name: "fabdeh/angular/rules",
|
|
265
376
|
plugins: { "@angular-eslint": angularEslint.tsPlugin },
|
|
266
377
|
processor: angularEslint.processInlineTemplates,
|
|
@@ -348,7 +459,7 @@ async function angular(options = {}) {
|
|
|
348
459
|
...enableAccessibilityRules ? angularEslint.configs.templateAccessibility.find((c) => c.name === "angular-eslint/template-accessibility")?.rules : {},
|
|
349
460
|
...htmlOverrides
|
|
350
461
|
}
|
|
351
|
-
}
|
|
462
|
+
}];
|
|
352
463
|
}
|
|
353
464
|
//#endregion
|
|
354
465
|
//#region src/configs/comments.ts
|
|
@@ -362,7 +473,7 @@ async function angular(options = {}) {
|
|
|
362
473
|
* @returns The configuration array for ESLint comments rules.
|
|
363
474
|
*/
|
|
364
475
|
function comments() {
|
|
365
|
-
return
|
|
476
|
+
return [{
|
|
366
477
|
name: "fabdeh/comments/rules",
|
|
367
478
|
files: [GLOB_SRC],
|
|
368
479
|
plugins: { "@eslint-community/eslint-comments": eslintComments },
|
|
@@ -374,196 +485,7 @@ function comments() {
|
|
|
374
485
|
"@eslint-community/eslint-comments/no-unused-disable": "error",
|
|
375
486
|
"@eslint-community/eslint-comments/no-unused-enable": "error"
|
|
376
487
|
}
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
//#endregion
|
|
380
|
-
//#region src/configs/stylistic.ts
|
|
381
|
-
const STYLISTIC_CONFIG_DEFAULT = {
|
|
382
|
-
semi: true,
|
|
383
|
-
arrowParens: true,
|
|
384
|
-
braceStyle: "1tbs",
|
|
385
|
-
quoteProps: "as-needed"
|
|
386
|
-
};
|
|
387
|
-
/**
|
|
388
|
-
* Generates a stylistic ESLint configuration.
|
|
389
|
-
*
|
|
390
|
-
* @param [options] - Optional configuration options to customize the stylistic rules.
|
|
391
|
-
* @returns A promise that resolves to an array of ESLint configurations.
|
|
392
|
-
* @example
|
|
393
|
-
* const config = await stylistic({ semi: false });
|
|
394
|
-
*/
|
|
395
|
-
async function stylistic(options = {}) {
|
|
396
|
-
const stylisticOptions = {
|
|
397
|
-
...STYLISTIC_CONFIG_DEFAULT,
|
|
398
|
-
...typeof options.stylistic === "boolean" ? {} : options.stylistic
|
|
399
|
-
};
|
|
400
|
-
const stylisticPlugin = await interopDefault(import("@stylistic/eslint-plugin"));
|
|
401
|
-
const config = stylisticPlugin.configs.customize(stylisticOptions);
|
|
402
|
-
return tseslint.config({
|
|
403
|
-
name: "fabdeh/stylistic/rules",
|
|
404
|
-
files: [GLOB_SRC],
|
|
405
|
-
plugins: { "@stylistic": stylisticPlugin },
|
|
406
|
-
rules: {
|
|
407
|
-
...config.rules,
|
|
408
|
-
"@stylistic/comma-dangle": ["error", {
|
|
409
|
-
arrays: "always-multiline",
|
|
410
|
-
objects: "always-multiline"
|
|
411
|
-
}],
|
|
412
|
-
"@stylistic/no-extra-semi": "error",
|
|
413
|
-
"@stylistic/operator-linebreak": [
|
|
414
|
-
"error",
|
|
415
|
-
"after",
|
|
416
|
-
{ overrides: {
|
|
417
|
-
"?": "before",
|
|
418
|
-
":": "before"
|
|
419
|
-
} }
|
|
420
|
-
]
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
//#endregion
|
|
425
|
-
//#region src/configs/formatters.ts
|
|
426
|
-
/**
|
|
427
|
-
* Merges the provided Prettier options with any overrides.
|
|
428
|
-
*
|
|
429
|
-
* @param options - The base Prettier options to merge.
|
|
430
|
-
* @param overrides - Required overrides for the Prettier options. Must include a `parser` property.
|
|
431
|
-
* @returns The merged Prettier options.
|
|
432
|
-
*/
|
|
433
|
-
function mergePrettierOptions(options, overrides) {
|
|
434
|
-
return {
|
|
435
|
-
...options,
|
|
436
|
-
...overrides,
|
|
437
|
-
plugins: [...overrides.plugins ?? [], ...options.plugins ?? []]
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Configures and returns an array of formatters based on the provided options.
|
|
442
|
-
*
|
|
443
|
-
* @param options - The options for configuring the formatters. If set to `true`, default options will be used.
|
|
444
|
-
* @param stylistic - The stylistic options for the formatters.
|
|
445
|
-
* @param hasAngularTemplateParser - Optional argument which indicates whether angular rules already registered the template parser or not.
|
|
446
|
-
* @returns A promise that resolves to a `TypedConfigArray` containing the configured formatters.
|
|
447
|
-
*/
|
|
448
|
-
async function formatters(options = {}, stylistic = {}, hasAngularTemplateParser = false) {
|
|
449
|
-
if (options === true) {
|
|
450
|
-
const isPrettierPluginXmlInScope = isPackageInScope("@prettier/plugin-xml");
|
|
451
|
-
options = {
|
|
452
|
-
css: true,
|
|
453
|
-
graphql: true,
|
|
454
|
-
html: true,
|
|
455
|
-
markdown: true,
|
|
456
|
-
slidev: isPackageExists("@slidev/cli"),
|
|
457
|
-
svg: isPrettierPluginXmlInScope,
|
|
458
|
-
xml: isPrettierPluginXmlInScope
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
await ensurePackages([
|
|
462
|
-
"eslint-plugin-format",
|
|
463
|
-
options.markdown && options.slidev ? "prettier-plugin-slidev" : void 0,
|
|
464
|
-
options.xml || options.svg ? "@prettier/plugin-xml" : void 0
|
|
465
|
-
]);
|
|
466
|
-
const { indent, quotes, semi } = {
|
|
467
|
-
...STYLISTIC_CONFIG_DEFAULT,
|
|
468
|
-
...stylistic
|
|
469
|
-
};
|
|
470
|
-
const prettierOptions = {
|
|
471
|
-
endOfLine: "auto",
|
|
472
|
-
printWidth: 120,
|
|
473
|
-
semi,
|
|
474
|
-
singleQuote: quotes === "single",
|
|
475
|
-
tabWidth: typeof indent === "number" ? indent : 2,
|
|
476
|
-
trailingComma: "all",
|
|
477
|
-
useTabs: indent === "tab",
|
|
478
|
-
...options.options
|
|
479
|
-
};
|
|
480
|
-
const prettierXmlOptions = {
|
|
481
|
-
xmlQuoteAttributes: "double",
|
|
482
|
-
xmlSelfClosingSpace: true,
|
|
483
|
-
xmlSortAttributesByKey: false,
|
|
484
|
-
xmlWhitespaceSensitivity: "ignore"
|
|
485
|
-
};
|
|
486
|
-
const formatPlugin = await interopDefault(import("eslint-plugin-format"));
|
|
487
|
-
const configs = [{
|
|
488
|
-
name: "fabdeh/formatter/setup",
|
|
489
|
-
plugins: { format: formatPlugin }
|
|
490
488
|
}];
|
|
491
|
-
if (options.css) configs.push({
|
|
492
|
-
name: "fabdeh/formatter/css",
|
|
493
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
494
|
-
files: [GLOB_CSS, GLOB_POSTCSS],
|
|
495
|
-
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "css" })] }
|
|
496
|
-
}, {
|
|
497
|
-
name: "fabdeh/formatter/scss",
|
|
498
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
499
|
-
files: [GLOB_SCSS],
|
|
500
|
-
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "scss" })] }
|
|
501
|
-
}, {
|
|
502
|
-
name: "fabdeh/formatter/less",
|
|
503
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
504
|
-
files: [GLOB_LESS],
|
|
505
|
-
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "less" })] }
|
|
506
|
-
});
|
|
507
|
-
if (options.html) configs.push({
|
|
508
|
-
name: "fabdeh/formatter/html",
|
|
509
|
-
...hasAngularTemplateParser ? {} : { languageOptions: { parser: formatPlugin.parserPlain } },
|
|
510
|
-
files: [GLOB_HTML],
|
|
511
|
-
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "html" })] }
|
|
512
|
-
});
|
|
513
|
-
if (options.xml) configs.push({
|
|
514
|
-
name: "fabdeh/formatter/xml",
|
|
515
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
516
|
-
files: [GLOB_XML],
|
|
517
|
-
rules: { "format/prettier": ["error", mergePrettierOptions({
|
|
518
|
-
...prettierXmlOptions,
|
|
519
|
-
...prettierOptions
|
|
520
|
-
}, {
|
|
521
|
-
parser: "xml",
|
|
522
|
-
plugins: ["@prettier/plugin-xml"]
|
|
523
|
-
})] }
|
|
524
|
-
});
|
|
525
|
-
if (options.svg) configs.push({
|
|
526
|
-
name: "fabdeh/formatter/svg",
|
|
527
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
528
|
-
files: [GLOB_SVG],
|
|
529
|
-
rules: { "format/prettier": ["error", mergePrettierOptions({
|
|
530
|
-
...prettierXmlOptions,
|
|
531
|
-
...prettierOptions
|
|
532
|
-
}, {
|
|
533
|
-
parser: "xml",
|
|
534
|
-
plugins: ["@prettier/plugin-xml"]
|
|
535
|
-
})] }
|
|
536
|
-
});
|
|
537
|
-
if (options.markdown) {
|
|
538
|
-
const GLOB_SLIDEV = options.slidev ? options.slidev === true ? ["**/.slides.md"] : options.slidev.files : [];
|
|
539
|
-
configs.push({
|
|
540
|
-
name: "fabdeh/formatter/markdown",
|
|
541
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
542
|
-
files: [GLOB_MARKDOWN],
|
|
543
|
-
ignores: GLOB_SLIDEV,
|
|
544
|
-
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, {
|
|
545
|
-
parser: "markdown",
|
|
546
|
-
embeddedLanguageFormatting: "off"
|
|
547
|
-
})] }
|
|
548
|
-
});
|
|
549
|
-
if (options.slidev) configs.push({
|
|
550
|
-
name: "fabdeh/formatter/slidev",
|
|
551
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
552
|
-
files: GLOB_SLIDEV,
|
|
553
|
-
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, {
|
|
554
|
-
embeddedLanguageFormatting: "off",
|
|
555
|
-
parser: "slidev",
|
|
556
|
-
plugins: ["prettier-plugin-slidev"]
|
|
557
|
-
})] }
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
if (options.graphql) configs.push({
|
|
561
|
-
name: "fabdeh/formatter/graphql",
|
|
562
|
-
languageOptions: { parser: formatPlugin.parserPlain },
|
|
563
|
-
files: [GLOB_GRAPHQL],
|
|
564
|
-
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "graphql" })] }
|
|
565
|
-
});
|
|
566
|
-
return tseslint.config(configs);
|
|
567
489
|
}
|
|
568
490
|
//#endregion
|
|
569
491
|
//#region src/configs/ignore.ts
|
|
@@ -572,13 +494,13 @@ async function formatters(options = {}, stylistic = {}, hasAngularTemplateParser
|
|
|
572
494
|
*
|
|
573
495
|
* @param userIgnores - An array of user-defined glob patterns to ignore. Defaults to an empty array.
|
|
574
496
|
* @param fromFactory - An optional suffix to add to the config name.
|
|
575
|
-
* @returns A
|
|
497
|
+
* @returns A TypedConfig[] object containing the combined "ignore" patterns.
|
|
576
498
|
*/
|
|
577
499
|
function ignores(userIgnores = [], fromFactory) {
|
|
578
|
-
return
|
|
500
|
+
return [{
|
|
579
501
|
name: `fabdeh/ignores${fromFactory ? `/${fromFactory}` : ""}`,
|
|
580
502
|
ignores: [...!fromFactory || fromFactory === "workspace" ? GLOB_EXCLUDE : [], ...userIgnores]
|
|
581
|
-
}
|
|
503
|
+
}];
|
|
582
504
|
}
|
|
583
505
|
//#endregion
|
|
584
506
|
//#region src/configs/imports.ts
|
|
@@ -587,11 +509,11 @@ function ignores(userIgnores = [], fromFactory) {
|
|
|
587
509
|
*
|
|
588
510
|
* @param options - An object containing stylistic options.
|
|
589
511
|
* @param options.stylistic - A boolean indicating whether to include stylistic rules. Defaults to true.
|
|
590
|
-
* @returns A
|
|
512
|
+
* @returns A TypedConfig[] object with the specified import rules.
|
|
591
513
|
*/
|
|
592
514
|
function imports(options = {}) {
|
|
593
515
|
const { stylistic = true } = options;
|
|
594
|
-
return
|
|
516
|
+
return [{
|
|
595
517
|
name: "fabdeh/imports/rules",
|
|
596
518
|
files: [GLOB_SRC],
|
|
597
519
|
plugins: { "import-x": importX },
|
|
@@ -625,7 +547,7 @@ function imports(options = {}) {
|
|
|
625
547
|
"import-x/named": "off",
|
|
626
548
|
"import-x/no-deprecated": "off"
|
|
627
549
|
}
|
|
628
|
-
}
|
|
550
|
+
}];
|
|
629
551
|
}
|
|
630
552
|
//#endregion
|
|
631
553
|
//#region src/configs/javascript.ts
|
|
@@ -645,8 +567,8 @@ function imports(options = {}) {
|
|
|
645
567
|
* ```
|
|
646
568
|
*/
|
|
647
569
|
function javascript(options = {}) {
|
|
648
|
-
const { overrides = {} } = options;
|
|
649
|
-
return
|
|
570
|
+
const { isInEditor = false, overrides = {} } = options;
|
|
571
|
+
return [{
|
|
650
572
|
name: "fabdeh/javascript/setup",
|
|
651
573
|
languageOptions: {
|
|
652
574
|
ecmaVersion: "latest",
|
|
@@ -861,7 +783,10 @@ function javascript(options = {}) {
|
|
|
861
783
|
singleReturnOnly: true,
|
|
862
784
|
allowNamedFunctions: true
|
|
863
785
|
}],
|
|
864
|
-
"prefer-const": "error",
|
|
786
|
+
"prefer-const": [isInEditor ? "warn" : "error", {
|
|
787
|
+
destructuring: "all",
|
|
788
|
+
ignoreReadBeforeAssign: true
|
|
789
|
+
}],
|
|
865
790
|
"prefer-exponentiation-operator": "error",
|
|
866
791
|
"prefer-object-spread": "error",
|
|
867
792
|
"prefer-promise-reject-errors": "error",
|
|
@@ -874,7 +799,7 @@ function javascript(options = {}) {
|
|
|
874
799
|
"symbol-description": "error",
|
|
875
800
|
"unicode-bom": ["error", "never"],
|
|
876
801
|
"use-isnan": ["error", { enforceForIndexOf: true }],
|
|
877
|
-
"unused-imports/no-unused-imports": "error",
|
|
802
|
+
"unused-imports/no-unused-imports": isInEditor ? "warn" : "error",
|
|
878
803
|
"unused-imports/no-unused-vars": ["error", {
|
|
879
804
|
args: "after-used",
|
|
880
805
|
argsIgnorePattern: "^_",
|
|
@@ -897,7 +822,7 @@ function javascript(options = {}) {
|
|
|
897
822
|
"@typescript-eslint/no-this-alias": "error",
|
|
898
823
|
...overrides
|
|
899
824
|
}
|
|
900
|
-
}
|
|
825
|
+
}];
|
|
901
826
|
}
|
|
902
827
|
//#endregion
|
|
903
828
|
//#region src/configs/jsdoc.ts
|
|
@@ -973,7 +898,7 @@ function getJsDocRules(level, stylistic, mode) {
|
|
|
973
898
|
*/
|
|
974
899
|
function jsdoc(options = {}) {
|
|
975
900
|
const { stylistic = true } = options;
|
|
976
|
-
return
|
|
901
|
+
return [{
|
|
977
902
|
name: "fabdeh/jsdoc/rules",
|
|
978
903
|
files: [GLOB_SRC],
|
|
979
904
|
plugins: { jsdoc: jsdocPlugin },
|
|
@@ -982,7 +907,7 @@ function jsdoc(options = {}) {
|
|
|
982
907
|
name: "fabdeh/jsdoc/ts-only/rules",
|
|
983
908
|
files: [GLOB_TS],
|
|
984
909
|
rules: getJsDocRules("warn", !!stylistic, "tsOnly")
|
|
985
|
-
}
|
|
910
|
+
}];
|
|
986
911
|
}
|
|
987
912
|
//#endregion
|
|
988
913
|
//#region src/configs/jsonc.ts
|
|
@@ -993,7 +918,7 @@ function jsdoc(options = {}) {
|
|
|
993
918
|
* @param options.files - An array of glob patterns to specify the JSONC files to lint. Defaults to `[GLOB_JSON, GLOB_JSON5, GLOB_JSONC]`.
|
|
994
919
|
* @param options.overrides - Additional rules or configurations to override the default settings.
|
|
995
920
|
* @param options.stylistic - A boolean or object to enable or configure stylistic rules. Defaults to `true`.
|
|
996
|
-
* @returns A promise that resolves to a `
|
|
921
|
+
* @returns A promise that resolves to a `TypedConfig[]` containing the ESLint configuration.
|
|
997
922
|
* @example
|
|
998
923
|
* ```typescript
|
|
999
924
|
* const config = await jsonc({
|
|
@@ -1012,7 +937,7 @@ async function jsonc(options = {}) {
|
|
|
1012
937
|
], overrides = {}, stylistic = true } = options;
|
|
1013
938
|
const { indent = 2 } = typeof stylistic === "object" ? stylistic : {};
|
|
1014
939
|
const [jsoncPlugin, jsoncParser] = await Promise.all([interopDefault(import("eslint-plugin-jsonc")), interopDefault(import("jsonc-eslint-parser"))]);
|
|
1015
|
-
return
|
|
940
|
+
return [{
|
|
1016
941
|
name: "fabdeh/jsonc/setup",
|
|
1017
942
|
plugins: { jsonc: jsoncPlugin }
|
|
1018
943
|
}, {
|
|
@@ -1066,7 +991,7 @@ async function jsonc(options = {}) {
|
|
|
1066
991
|
} : {},
|
|
1067
992
|
...overrides
|
|
1068
993
|
}
|
|
1069
|
-
}
|
|
994
|
+
}];
|
|
1070
995
|
}
|
|
1071
996
|
//#endregion
|
|
1072
997
|
//#region src/configs/markdown.ts
|
|
@@ -1079,7 +1004,7 @@ async function jsonc(options = {}) {
|
|
|
1079
1004
|
* @param options - An object containing file and override options.
|
|
1080
1005
|
* @param options.files - An array of glob patterns to specify the Markdown files to lint.
|
|
1081
1006
|
* @param options.overrides - An object containing rule overrides.
|
|
1082
|
-
* @returns A promise that resolves to a
|
|
1007
|
+
* @returns A promise that resolves to a TypedConfig[] containing the ESLint configurations.
|
|
1083
1008
|
* @example
|
|
1084
1009
|
* ```typescript
|
|
1085
1010
|
* const config = await markdown({
|
|
@@ -1093,75 +1018,81 @@ async function jsonc(options = {}) {
|
|
|
1093
1018
|
async function markdown(options = {}) {
|
|
1094
1019
|
const { files = [GLOB_MARKDOWN], overrides = {} } = options;
|
|
1095
1020
|
const markdownPlugin = await interopDefault(import("@eslint/markdown"));
|
|
1096
|
-
return
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1021
|
+
return [
|
|
1022
|
+
{
|
|
1023
|
+
name: "fabdeh/markdown/setup",
|
|
1024
|
+
plugins: { markdown: markdownPlugin }
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
name: "fabdeh/markdown/processor",
|
|
1028
|
+
files,
|
|
1029
|
+
ignores: [GLOB_MARKDOWN_IN_MARKDOWN],
|
|
1030
|
+
processor: mergeProcessors([markdownPlugin.processors.markdown, processorPassThrough])
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
name: "fabdeh/markdown/parser",
|
|
1034
|
+
files,
|
|
1035
|
+
languageOptions: { parser: {
|
|
1036
|
+
meta: { name: "parser-plain" },
|
|
1037
|
+
parseForESLint: (code) => ({
|
|
1038
|
+
ast: {
|
|
1039
|
+
body: [],
|
|
1040
|
+
comments: [],
|
|
1041
|
+
loc: {
|
|
1042
|
+
end: code.length,
|
|
1043
|
+
start: 0
|
|
1044
|
+
},
|
|
1045
|
+
range: [0, code.length],
|
|
1046
|
+
tokens: [],
|
|
1047
|
+
type: "Program"
|
|
1116
1048
|
},
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
"markdown/no-duplicate-headings": "error"
|
|
1049
|
+
scopeManager: null,
|
|
1050
|
+
services: { isPlain: true },
|
|
1051
|
+
visitorKeys: { Program: [] }
|
|
1052
|
+
})
|
|
1053
|
+
} }
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
name: "fabdeh/markdown/disables",
|
|
1057
|
+
languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
|
|
1058
|
+
files: [GLOB_MARKDOWN_CODE],
|
|
1059
|
+
rules: {
|
|
1060
|
+
...tseslint.configs.disableTypeChecked.rules,
|
|
1061
|
+
"import-x/newline-after-import": "off",
|
|
1062
|
+
"no-alert": "off",
|
|
1063
|
+
"no-console": "off",
|
|
1064
|
+
"no-labels": "off",
|
|
1065
|
+
"no-lone-blocks": "off",
|
|
1066
|
+
"no-restricted-syntax": "off",
|
|
1067
|
+
"no-undef": "off",
|
|
1068
|
+
"no-unused-expressions": "off",
|
|
1069
|
+
"no-unused-labels": "off",
|
|
1070
|
+
"no-unused-vars": "off",
|
|
1071
|
+
"@stylistic/comma-dangle": "off",
|
|
1072
|
+
"@stylistic/eol-last": "off",
|
|
1073
|
+
"@typescript-eslint/consistent-type-imports": "off",
|
|
1074
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
1075
|
+
"@typescript-eslint/no-namespace": "off",
|
|
1076
|
+
"@typescript-eslint/no-redeclare": "off",
|
|
1077
|
+
"@typescript-eslint/no-require-imports": "off",
|
|
1078
|
+
"@typescript-eslint/no-unused-expressions": "off",
|
|
1079
|
+
"@typescript-eslint/no-unused-vars": "off",
|
|
1080
|
+
"@typescript-eslint/no-use-before-define": "off",
|
|
1081
|
+
"unicode-bom": "off",
|
|
1082
|
+
"unused-imports/no-unused-imports": "off",
|
|
1083
|
+
"unused-imports/no-unused-vars": "off",
|
|
1084
|
+
...overrides
|
|
1085
|
+
}
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
name: "fabdeh/markdown/rules",
|
|
1089
|
+
files,
|
|
1090
|
+
rules: {
|
|
1091
|
+
...markdownPlugin.configs.recommended.at(0)?.rules,
|
|
1092
|
+
"markdown/no-duplicate-headings": "error"
|
|
1093
|
+
}
|
|
1163
1094
|
}
|
|
1164
|
-
|
|
1095
|
+
];
|
|
1165
1096
|
}
|
|
1166
1097
|
//#endregion
|
|
1167
1098
|
//#region src/configs/rules-configs/naming-convention.ts
|
|
@@ -1272,15 +1203,16 @@ async function ngrx(options = {}) {
|
|
|
1272
1203
|
const { store = isPackageExists("@ngrx/store"), effects = isPackageExists("@ngrx/effects"), signals = isPackageExists("@ngrx/signals"), useRelaxedNamingConventionForCamelAndPascalCases = false } = options;
|
|
1273
1204
|
const configs = [];
|
|
1274
1205
|
let addOperatorsRules = false;
|
|
1206
|
+
const registerPluginFiles = [];
|
|
1275
1207
|
const ngrxOperatorsFiles = [];
|
|
1276
1208
|
if (store) {
|
|
1277
1209
|
const { files = DEFAULT_STORE_GLOB, enforceOperatorsRules = isPackageExists("@ngrx/operators"), overrides = {} } = typeof store === "object" ? store : {};
|
|
1278
1210
|
addOperatorsRules ||= enforceOperatorsRules;
|
|
1279
1211
|
ngrxOperatorsFiles.push(files);
|
|
1212
|
+
registerPluginFiles.push(files);
|
|
1280
1213
|
configs.push({
|
|
1281
1214
|
name: "fabdeh/ngrx-store/rules",
|
|
1282
1215
|
files,
|
|
1283
|
-
plugins: { "@ngrx": ngrxPlugin },
|
|
1284
1216
|
rules: {
|
|
1285
1217
|
...ngrxPlugin.configs.store.find((c) => c.name === "ngrx/store")?.rules,
|
|
1286
1218
|
"@typescript-eslint/naming-convention": [
|
|
@@ -1314,10 +1246,10 @@ async function ngrx(options = {}) {
|
|
|
1314
1246
|
const { files = DEFAULT_EFFECTS_GLOB, enforceOperatorsRules = isPackageExists("@ngrx/operators"), overrides = {} } = typeof effects === "object" ? effects : {};
|
|
1315
1247
|
addOperatorsRules ||= enforceOperatorsRules;
|
|
1316
1248
|
ngrxOperatorsFiles.push(files);
|
|
1249
|
+
registerPluginFiles.push(files);
|
|
1317
1250
|
configs.push({
|
|
1318
1251
|
name: "fabdeh/ngrx-effects/rules",
|
|
1319
1252
|
files,
|
|
1320
|
-
plugins: { "@ngrx": ngrxPlugin },
|
|
1321
1253
|
rules: {
|
|
1322
1254
|
...ngrxPlugin.configs.effects.find((c) => c.name === "ngrx/effects")?.rules,
|
|
1323
1255
|
"@typescript-eslint/naming-convention": [
|
|
@@ -1344,10 +1276,10 @@ async function ngrx(options = {}) {
|
|
|
1344
1276
|
const { files = DEFAULT_SIGNALS_GLOB, enforceOperatorsRules = isPackageExists("@ngrx/operators"), overrides = {} } = typeof signals === "object" ? signals : {};
|
|
1345
1277
|
addOperatorsRules ||= enforceOperatorsRules;
|
|
1346
1278
|
ngrxOperatorsFiles.push(files);
|
|
1279
|
+
registerPluginFiles.push(files);
|
|
1347
1280
|
configs.push({
|
|
1348
1281
|
name: "fabdeh/ngrx-signals/rules",
|
|
1349
1282
|
files,
|
|
1350
|
-
plugins: { "@ngrx": ngrxPlugin },
|
|
1351
1283
|
rules: {
|
|
1352
1284
|
...ngrxPlugin.configs.signals.find((c) => c.name === "ngrx/signals")?.rules,
|
|
1353
1285
|
"@typescript-eslint/naming-convention": [
|
|
@@ -1378,10 +1310,14 @@ async function ngrx(options = {}) {
|
|
|
1378
1310
|
if (addOperatorsRules) configs.push({
|
|
1379
1311
|
name: "fabdeh/ngrx-operators/rules",
|
|
1380
1312
|
files: [...ngrxOperatorsFiles],
|
|
1381
|
-
plugins: { "@ngrx": ngrxPlugin },
|
|
1382
1313
|
rules: { ...ngrxPlugin.configs.operators.find((c) => c.name === "ngrx/operators")?.rules }
|
|
1383
1314
|
});
|
|
1384
|
-
|
|
1315
|
+
if (registerPluginFiles.length > 0) configs.unshift({
|
|
1316
|
+
name: "fabdeh/ngrx/setup",
|
|
1317
|
+
files: [...registerPluginFiles],
|
|
1318
|
+
plugins: { "@ngrx": ngrxPlugin.configs.store.find((c) => c.name === "ngrx/base")?.plugins?.["@ngrx"] ?? {} }
|
|
1319
|
+
});
|
|
1320
|
+
return configs;
|
|
1385
1321
|
}
|
|
1386
1322
|
//#endregion
|
|
1387
1323
|
//#region src/configs/node.ts
|
|
@@ -1391,7 +1327,7 @@ async function ngrx(options = {}) {
|
|
|
1391
1327
|
* @returns An array defining Node.js rules, plugins, and their configurations.
|
|
1392
1328
|
*/
|
|
1393
1329
|
function node() {
|
|
1394
|
-
return
|
|
1330
|
+
return [{
|
|
1395
1331
|
name: "fabdeh/node/rules",
|
|
1396
1332
|
files: [GLOB_SRC],
|
|
1397
1333
|
plugins: { n: nodePlugin },
|
|
@@ -1408,7 +1344,7 @@ function node() {
|
|
|
1408
1344
|
"n/prefer-promises/fs": "error",
|
|
1409
1345
|
"n/process-exit-as-throw": "error"
|
|
1410
1346
|
}
|
|
1411
|
-
}
|
|
1347
|
+
}];
|
|
1412
1348
|
}
|
|
1413
1349
|
//#endregion
|
|
1414
1350
|
//#region src/configs/rules-configs/perfectionist-groups.ts
|
|
@@ -1470,7 +1406,7 @@ const SORT_UNION_OR_INTERSECTION_GROUPS = [
|
|
|
1470
1406
|
*/
|
|
1471
1407
|
function perfectionist() {
|
|
1472
1408
|
const rootDir = getWorkspaceRoot(process.cwd(), process.cwd());
|
|
1473
|
-
return
|
|
1409
|
+
return [{
|
|
1474
1410
|
name: "fabdeh/perfectionist/rules",
|
|
1475
1411
|
files: [GLOB_SRC],
|
|
1476
1412
|
plugins: { perfectionist: perfectionistPlugin },
|
|
@@ -1512,41 +1448,204 @@ function perfectionist() {
|
|
|
1512
1448
|
type: "natural"
|
|
1513
1449
|
}]
|
|
1514
1450
|
}
|
|
1515
|
-
}
|
|
1451
|
+
}];
|
|
1452
|
+
}
|
|
1453
|
+
//#endregion
|
|
1454
|
+
//#region src/configs/playwright.ts
|
|
1455
|
+
/**
|
|
1456
|
+
* Configures and returns an ESLint flat config for Playwright test files.
|
|
1457
|
+
*
|
|
1458
|
+
* @param [options] - Options used to customize the Playwright config.
|
|
1459
|
+
* @param [options.e2eFolderPath] - The path to the e2e folder to prepend to each `options.files` glob pattern (defaults to `e2e`).
|
|
1460
|
+
* @param [options.files] - File globs to target (defaults to `GLOB_TESTS`).
|
|
1461
|
+
* @param [options.overrides] - Custom ESLint rule overrides merged last.
|
|
1462
|
+
* @returns A promise that resolves to a single-entry ESLint config array.
|
|
1463
|
+
* @example
|
|
1464
|
+
* const config = await playwright({
|
|
1465
|
+
* e2eFolderPath: 'tests/e2e',
|
|
1466
|
+
* files: ['**\/*.test.ts'], // will become 'tests\/e2e\/**\/*.test.ts' because of the e2eFolderPath option
|
|
1467
|
+
* overrides: {
|
|
1468
|
+
* 'playwright/no-page-pause': 'off',
|
|
1469
|
+
* },
|
|
1470
|
+
* });
|
|
1471
|
+
*/
|
|
1472
|
+
async function playwright(options = {}) {
|
|
1473
|
+
const { e2eFolderPath = "e2e", files = GLOB_TESTS.map((glob) => convertPathToPosix(join(e2eFolderPath, glob))), overrides = {} } = options;
|
|
1474
|
+
if (!isDirectory(e2eFolderPath)) return [];
|
|
1475
|
+
const playwrightPlugin = await interopDefault(import("eslint-plugin-playwright"));
|
|
1476
|
+
return [{
|
|
1477
|
+
name: "fabdeh/playwright/rules",
|
|
1478
|
+
plugins: { playwright: playwrightPlugin },
|
|
1479
|
+
files,
|
|
1480
|
+
rules: {
|
|
1481
|
+
...playwrightPlugin.configs.recommended.rules,
|
|
1482
|
+
"max-lines": "off",
|
|
1483
|
+
"@typescript-eslint/consistent-type-assertions": "off",
|
|
1484
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
1485
|
+
"@typescript-eslint/no-unsafe-assignment": "off",
|
|
1486
|
+
"@typescript-eslint/no-unsafe-call": "off",
|
|
1487
|
+
"@typescript-eslint/no-unsafe-member-access": "off",
|
|
1488
|
+
"@typescript-eslint/unbound-method": "off",
|
|
1489
|
+
"unicorn/no-null": "off",
|
|
1490
|
+
"playwright/no-get-by-title": "error",
|
|
1491
|
+
"playwright/no-nth-methods": "error",
|
|
1492
|
+
"playwright/prefer-comparison-matcher": "error",
|
|
1493
|
+
"playwright/prefer-equality-matcher": "error",
|
|
1494
|
+
"playwright/prefer-lowercase-title": ["error", { allowedPrefixes: [
|
|
1495
|
+
"GET",
|
|
1496
|
+
"POST",
|
|
1497
|
+
"PUT",
|
|
1498
|
+
"DELETE",
|
|
1499
|
+
"PATCH",
|
|
1500
|
+
"HEAD",
|
|
1501
|
+
"OPTIONS"
|
|
1502
|
+
] }],
|
|
1503
|
+
"playwright/prefer-native-locators": "error",
|
|
1504
|
+
"playwright/prefer-to-be": "error",
|
|
1505
|
+
"playwright/prefer-to-contain": "error",
|
|
1506
|
+
...getJsDocRules("off", true, "both"),
|
|
1507
|
+
...overrides
|
|
1508
|
+
}
|
|
1509
|
+
}];
|
|
1516
1510
|
}
|
|
1517
1511
|
//#endregion
|
|
1518
1512
|
//#region src/configs/pnpm.ts
|
|
1519
1513
|
/**
|
|
1514
|
+
* Detects whether the current PNPM workspace uses catalog definitions.
|
|
1515
|
+
*
|
|
1516
|
+
* Searches for a `pnpm-workspace.yaml` file and checks whether it contains
|
|
1517
|
+
* either the `catalog:` or `catalogs:` keys, which are used to define shared
|
|
1518
|
+
* dependency version catalogs in PNPM workspaces.
|
|
1519
|
+
*
|
|
1520
|
+
* @returns `true` when catalog configuration is present; otherwise `false`.
|
|
1521
|
+
*/
|
|
1522
|
+
async function detectCatalogUsage() {
|
|
1523
|
+
const workspaceFile = await findUp("pnpm-workspace.yaml");
|
|
1524
|
+
if (!workspaceFile) return false;
|
|
1525
|
+
const yaml = await readFile(workspaceFile, "utf-8");
|
|
1526
|
+
return yaml.includes("catalog:") || yaml.includes("catalogs:");
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1520
1529
|
* Generates an array containing configuration settings for PNPM workspace-specific rules and plugins.
|
|
1521
1530
|
*
|
|
1531
|
+
* @param options - The options
|
|
1522
1532
|
* @returns An array defining PNPM workspace rules, plugins, and their configurations.
|
|
1523
1533
|
*/
|
|
1524
|
-
async function pnpm() {
|
|
1525
|
-
const [pluginPnpm,
|
|
1534
|
+
async function pnpm(options = {}) {
|
|
1535
|
+
const [pluginPnpm, pluginYaml, yamlParser] = await Promise.all([
|
|
1526
1536
|
interopDefault(import("eslint-plugin-pnpm")),
|
|
1527
|
-
interopDefault(import("
|
|
1528
|
-
interopDefault(import("
|
|
1537
|
+
interopDefault(import("eslint-plugin-yml")),
|
|
1538
|
+
interopDefault(import("yaml-eslint-parser"))
|
|
1529
1539
|
]);
|
|
1530
|
-
|
|
1540
|
+
const { catalogs = await detectCatalogUsage(), isInEditor = false, json = true, sort = true, yaml = true } = options;
|
|
1541
|
+
const configs = [];
|
|
1542
|
+
if (json) configs.push({
|
|
1531
1543
|
name: "fabdeh/pnpm/package-json",
|
|
1532
1544
|
files: ["package.json", "**/package.json"],
|
|
1533
|
-
|
|
1545
|
+
language: "jsonc/x",
|
|
1534
1546
|
plugins: { pnpm: pluginPnpm },
|
|
1535
1547
|
rules: {
|
|
1536
|
-
"pnpm/json-enforce-catalog": "error",
|
|
1537
|
-
|
|
1538
|
-
|
|
1548
|
+
...catalogs ? { "pnpm/json-enforce-catalog": ["error", {
|
|
1549
|
+
autofix: !isInEditor,
|
|
1550
|
+
ignores: ["@types/vscode"]
|
|
1551
|
+
}] } : {},
|
|
1552
|
+
"pnpm/json-prefer-workspace-settings": ["error", { autofix: !isInEditor }],
|
|
1553
|
+
"pnpm/json-valid-catalog": ["error", { autofix: !isInEditor }]
|
|
1539
1554
|
}
|
|
1540
|
-
}
|
|
1555
|
+
});
|
|
1556
|
+
if (yaml) configs.push({
|
|
1541
1557
|
name: "fabdeh/pnpm/pnpm-workspace-yaml",
|
|
1542
1558
|
files: ["pnpm-workspace.yaml"],
|
|
1543
1559
|
languageOptions: { parser: yamlParser },
|
|
1544
1560
|
plugins: { pnpm: pluginPnpm },
|
|
1545
1561
|
rules: {
|
|
1562
|
+
"pnpm/yaml-enforce-settings": ["error", { settings: {
|
|
1563
|
+
shellEmulator: true,
|
|
1564
|
+
trustPolicy: "no-downgrade"
|
|
1565
|
+
} }],
|
|
1546
1566
|
"pnpm/yaml-no-duplicate-catalog-item": "error",
|
|
1547
1567
|
"pnpm/yaml-no-unused-catalog-item": "error"
|
|
1548
1568
|
}
|
|
1549
1569
|
});
|
|
1570
|
+
if (sort) configs.push({
|
|
1571
|
+
files: ["pnpm-workspace.yaml"],
|
|
1572
|
+
languageOptions: { parser: yamlParser },
|
|
1573
|
+
name: "antfu/pnpm/pnpm-workspace-yaml-sort",
|
|
1574
|
+
plugins: { yaml: pluginYaml },
|
|
1575
|
+
rules: { "yaml/sort-keys": [
|
|
1576
|
+
"error",
|
|
1577
|
+
{
|
|
1578
|
+
order: [
|
|
1579
|
+
...[
|
|
1580
|
+
"cacheDir",
|
|
1581
|
+
"catalogMode",
|
|
1582
|
+
"cleanupUnusedCatalogs",
|
|
1583
|
+
"dedupeDirectDeps",
|
|
1584
|
+
"deployAllFiles",
|
|
1585
|
+
"enablePrePostScripts",
|
|
1586
|
+
"engineStrict",
|
|
1587
|
+
"extendNodePath",
|
|
1588
|
+
"hoist",
|
|
1589
|
+
"hoistPattern",
|
|
1590
|
+
"hoistWorkspacePackages",
|
|
1591
|
+
"ignoreCompatibilityDb",
|
|
1592
|
+
"ignoreDepScripts",
|
|
1593
|
+
"ignoreScripts",
|
|
1594
|
+
"ignoreWorkspaceRootCheck",
|
|
1595
|
+
"managePackageManagerVersions",
|
|
1596
|
+
"minimumReleaseAge",
|
|
1597
|
+
"minimumReleaseAgeExclude",
|
|
1598
|
+
"modulesDir",
|
|
1599
|
+
"nodeLinker",
|
|
1600
|
+
"nodeVersion",
|
|
1601
|
+
"optimisticRepeatInstall",
|
|
1602
|
+
"packageManagerStrict",
|
|
1603
|
+
"packageManagerStrictVersion",
|
|
1604
|
+
"preferSymlinkedExecutables",
|
|
1605
|
+
"preferWorkspacePackages",
|
|
1606
|
+
"publicHoistPattern",
|
|
1607
|
+
"registrySupportsTimeField",
|
|
1608
|
+
"requiredScripts",
|
|
1609
|
+
"resolutionMode",
|
|
1610
|
+
"savePrefix",
|
|
1611
|
+
"scriptShell",
|
|
1612
|
+
"shamefullyHoist",
|
|
1613
|
+
"shellEmulator",
|
|
1614
|
+
"stateDir",
|
|
1615
|
+
"supportedArchitectures",
|
|
1616
|
+
"symlink",
|
|
1617
|
+
"tag",
|
|
1618
|
+
"trustPolicy",
|
|
1619
|
+
"trustPolicyExclude",
|
|
1620
|
+
"updateNotifier"
|
|
1621
|
+
],
|
|
1622
|
+
"packages",
|
|
1623
|
+
"overrides",
|
|
1624
|
+
"patchedDependencies",
|
|
1625
|
+
"catalog",
|
|
1626
|
+
"catalogs",
|
|
1627
|
+
...[
|
|
1628
|
+
"allowedDeprecatedVersions",
|
|
1629
|
+
"allowNonAppliedPatches",
|
|
1630
|
+
"configDependencies",
|
|
1631
|
+
"ignoredBuiltDependencies",
|
|
1632
|
+
"ignoredOptionalDependencies",
|
|
1633
|
+
"neverBuiltDependencies",
|
|
1634
|
+
"onlyBuiltDependencies",
|
|
1635
|
+
"onlyBuiltDependenciesFile",
|
|
1636
|
+
"packageExtensions",
|
|
1637
|
+
"peerDependencyRules"
|
|
1638
|
+
]
|
|
1639
|
+
],
|
|
1640
|
+
pathPattern: "^$"
|
|
1641
|
+
},
|
|
1642
|
+
{
|
|
1643
|
+
order: { type: "asc" },
|
|
1644
|
+
pathPattern: ".*"
|
|
1645
|
+
}
|
|
1646
|
+
] }
|
|
1647
|
+
});
|
|
1648
|
+
return configs;
|
|
1550
1649
|
}
|
|
1551
1650
|
//#endregion
|
|
1552
1651
|
//#region src/configs/regexp.ts
|
|
@@ -1560,7 +1659,7 @@ function regexp(options = {}) {
|
|
|
1560
1659
|
const { level, overrides } = options;
|
|
1561
1660
|
const config = configs["flat/recommended"];
|
|
1562
1661
|
const rules = Object.fromEntries(Object.entries(config.rules).map(([ruleName, ruleLevel]) => [ruleName, level === "warn" ? level : ruleLevel]));
|
|
1563
|
-
return
|
|
1662
|
+
return [{
|
|
1564
1663
|
name: "fabdeh/regexp/rules",
|
|
1565
1664
|
files: [GLOB_SRC],
|
|
1566
1665
|
plugins: { ...config.plugins },
|
|
@@ -1568,7 +1667,7 @@ function regexp(options = {}) {
|
|
|
1568
1667
|
...rules,
|
|
1569
1668
|
...overrides
|
|
1570
1669
|
}
|
|
1571
|
-
}
|
|
1670
|
+
}];
|
|
1572
1671
|
}
|
|
1573
1672
|
//#endregion
|
|
1574
1673
|
//#region src/configs/sort.ts
|
|
@@ -1586,7 +1685,7 @@ function regexp(options = {}) {
|
|
|
1586
1685
|
* @returns The ESLint configuration array with sorting rules.
|
|
1587
1686
|
*/
|
|
1588
1687
|
function sortPackageJson() {
|
|
1589
|
-
return
|
|
1688
|
+
return [{
|
|
1590
1689
|
name: "fabdeh/sort/package-json",
|
|
1591
1690
|
files: ["**/package.json"],
|
|
1592
1691
|
rules: {
|
|
@@ -1681,7 +1780,7 @@ function sortPackageJson() {
|
|
|
1681
1780
|
}
|
|
1682
1781
|
]
|
|
1683
1782
|
}
|
|
1684
|
-
}
|
|
1783
|
+
}];
|
|
1685
1784
|
}
|
|
1686
1785
|
/**
|
|
1687
1786
|
* Generates a TypeScript ESLint configuration array that enforces sorting rules for `tsconfig.json` files.
|
|
@@ -1693,7 +1792,7 @@ function sortPackageJson() {
|
|
|
1693
1792
|
* @returns The TypeScript ESLint configuration array with sorting rules.
|
|
1694
1793
|
*/
|
|
1695
1794
|
function sortTsConfig() {
|
|
1696
|
-
return
|
|
1795
|
+
return [{
|
|
1697
1796
|
name: "fabdeh/sort/tsconfig-json",
|
|
1698
1797
|
files: ["**/tsconfig.json", "**/tsconfig.*.json"],
|
|
1699
1798
|
rules: { "jsonc/sort-keys": [
|
|
@@ -1804,7 +1903,52 @@ function sortTsConfig() {
|
|
|
1804
1903
|
pathPattern: "^compilerOptions$"
|
|
1805
1904
|
}
|
|
1806
1905
|
] }
|
|
1807
|
-
}
|
|
1906
|
+
}];
|
|
1907
|
+
}
|
|
1908
|
+
//#endregion
|
|
1909
|
+
//#region src/configs/stylistic.ts
|
|
1910
|
+
const STYLISTIC_CONFIG_DEFAULT = {
|
|
1911
|
+
semi: true,
|
|
1912
|
+
arrowParens: true,
|
|
1913
|
+
braceStyle: "1tbs",
|
|
1914
|
+
quoteProps: "as-needed"
|
|
1915
|
+
};
|
|
1916
|
+
/**
|
|
1917
|
+
* Generates a stylistic ESLint configuration.
|
|
1918
|
+
*
|
|
1919
|
+
* @param [options] - Optional configuration options to customize the stylistic rules.
|
|
1920
|
+
* @returns A promise that resolves to an array of ESLint configurations.
|
|
1921
|
+
* @example
|
|
1922
|
+
* const config = await stylistic({ semi: false });
|
|
1923
|
+
*/
|
|
1924
|
+
async function stylistic(options = {}) {
|
|
1925
|
+
const stylisticOptions = {
|
|
1926
|
+
...STYLISTIC_CONFIG_DEFAULT,
|
|
1927
|
+
...typeof options.stylistic === "boolean" ? {} : options.stylistic
|
|
1928
|
+
};
|
|
1929
|
+
const stylisticPlugin = await interopDefault(import("@stylistic/eslint-plugin"));
|
|
1930
|
+
const config = stylisticPlugin.configs.customize(stylisticOptions);
|
|
1931
|
+
return [{
|
|
1932
|
+
name: "fabdeh/stylistic/rules",
|
|
1933
|
+
files: [GLOB_SRC],
|
|
1934
|
+
plugins: { "@stylistic": stylisticPlugin },
|
|
1935
|
+
rules: {
|
|
1936
|
+
...config.rules,
|
|
1937
|
+
"@stylistic/comma-dangle": ["error", {
|
|
1938
|
+
arrays: "always-multiline",
|
|
1939
|
+
objects: "always-multiline"
|
|
1940
|
+
}],
|
|
1941
|
+
"@stylistic/no-extra-semi": "error",
|
|
1942
|
+
"@stylistic/operator-linebreak": [
|
|
1943
|
+
"error",
|
|
1944
|
+
"after",
|
|
1945
|
+
{ overrides: {
|
|
1946
|
+
"?": "before",
|
|
1947
|
+
":": "before"
|
|
1948
|
+
} }
|
|
1949
|
+
]
|
|
1950
|
+
}
|
|
1951
|
+
}];
|
|
1808
1952
|
}
|
|
1809
1953
|
//#endregion
|
|
1810
1954
|
//#region src/configs/tailwindcss.ts
|
|
@@ -1838,8 +1982,8 @@ async function tailwindcss(options = {}) {
|
|
|
1838
1982
|
files = { files: filesGlob ?? [GLOB_SRC, "**/*.htm?(l)"] };
|
|
1839
1983
|
parserConfigs = [];
|
|
1840
1984
|
}
|
|
1841
|
-
return
|
|
1842
|
-
name: "
|
|
1985
|
+
return [...parserConfigs, {
|
|
1986
|
+
name: "fabdeh/tailwindcss/rules",
|
|
1843
1987
|
...files,
|
|
1844
1988
|
plugins: { "better-tailwindcss": betterTailwindcssPlugin },
|
|
1845
1989
|
settings: { "better-tailwindcss": settings },
|
|
@@ -1852,7 +1996,7 @@ async function tailwindcss(options = {}) {
|
|
|
1852
1996
|
"better-tailwindcss/no-restricted-classes": "error"
|
|
1853
1997
|
} : {}
|
|
1854
1998
|
}
|
|
1855
|
-
}
|
|
1999
|
+
}];
|
|
1856
2000
|
}
|
|
1857
2001
|
//#endregion
|
|
1858
2002
|
//#region src/configs/toml.ts
|
|
@@ -1869,10 +2013,9 @@ async function tailwindcss(options = {}) {
|
|
|
1869
2013
|
async function toml(options = {}) {
|
|
1870
2014
|
const { files = [GLOB_TOML], overrides = {}, stylistic = true } = options;
|
|
1871
2015
|
const { indent = 2 } = typeof stylistic === "object" ? stylistic : {};
|
|
1872
|
-
|
|
1873
|
-
return tseslint.config({
|
|
2016
|
+
return [{
|
|
1874
2017
|
name: "fabdeh/toml/setup",
|
|
1875
|
-
plugins: { toml:
|
|
2018
|
+
plugins: { toml: await interopDefault(import("eslint-plugin-toml")) }
|
|
1876
2019
|
}, {
|
|
1877
2020
|
name: "fabdeh/toml/rules",
|
|
1878
2021
|
files,
|
|
@@ -1902,7 +2045,7 @@ async function toml(options = {}) {
|
|
|
1902
2045
|
} : {},
|
|
1903
2046
|
...overrides
|
|
1904
2047
|
}
|
|
1905
|
-
}
|
|
2048
|
+
}];
|
|
1906
2049
|
}
|
|
1907
2050
|
//#endregion
|
|
1908
2051
|
//#region src/configs/rules-configs/member-ordering.ts
|
|
@@ -1950,7 +2093,7 @@ const MEMBER_ORDERING_OPTIONS = { default: [
|
|
|
1950
2093
|
* @param options.parserOptions - Options for the TypeScript parser.
|
|
1951
2094
|
* @param options.overrides - Additional rule overrides.
|
|
1952
2095
|
* @param isWorkspaceProject - A boolean indicating whether the project is a workspace project. Defaults to false.
|
|
1953
|
-
* @returns A
|
|
2096
|
+
* @returns A TypedConfig[] containing the TypeScript ESLint configuration.
|
|
1954
2097
|
*/
|
|
1955
2098
|
async function typescript(options = {}, isWorkspaceProject = false) {
|
|
1956
2099
|
const { enableErasableSyntaxOnly = false, overrides = {}, parserOptions = {}, stylistic = true, type = "app", useRelaxedNamingConventionForCamelAndPascalCases = false } = options;
|
|
@@ -1964,7 +2107,7 @@ async function typescript(options = {}, isWorkspaceProject = false) {
|
|
|
1964
2107
|
}
|
|
1965
2108
|
const tsconfigRootDir = getWorkspaceRoot(process.cwd(), process.cwd());
|
|
1966
2109
|
const defaultProject = getTsConfigFileName(tsconfigRootDir);
|
|
1967
|
-
return
|
|
2110
|
+
return [{
|
|
1968
2111
|
name: `fabdeh/${type}/typescript/setup`,
|
|
1969
2112
|
files: [GLOB_TS],
|
|
1970
2113
|
ignores: [`${GLOB_MARKDOWN}/**`],
|
|
@@ -2066,7 +2209,7 @@ async function typescript(options = {}, isWorkspaceProject = false) {
|
|
|
2066
2209
|
...erasableSyntaxOnlyRules,
|
|
2067
2210
|
...overrides
|
|
2068
2211
|
}
|
|
2069
|
-
}
|
|
2212
|
+
}];
|
|
2070
2213
|
}
|
|
2071
2214
|
//#endregion
|
|
2072
2215
|
//#region src/configs/unicorn.ts
|
|
@@ -2077,7 +2220,7 @@ async function typescript(options = {}, isWorkspaceProject = false) {
|
|
|
2077
2220
|
* @returns The configuration array for the Unicorn plugin.
|
|
2078
2221
|
*/
|
|
2079
2222
|
function unicorn(options = {}) {
|
|
2080
|
-
return
|
|
2223
|
+
return [{
|
|
2081
2224
|
name: "fabdeh/unicorn/rules",
|
|
2082
2225
|
files: [GLOB_SRC],
|
|
2083
2226
|
plugins: { unicorn: unicornPlugin },
|
|
@@ -2178,7 +2321,7 @@ function unicorn(options = {}) {
|
|
|
2178
2321
|
"unicorn/require-post-message-target-origin": "error",
|
|
2179
2322
|
"unicorn/throw-new-error": "error"
|
|
2180
2323
|
} }
|
|
2181
|
-
}
|
|
2324
|
+
}];
|
|
2182
2325
|
}
|
|
2183
2326
|
//#endregion
|
|
2184
2327
|
//#region src/configs/vitest.ts
|
|
@@ -2186,27 +2329,30 @@ function unicorn(options = {}) {
|
|
|
2186
2329
|
* Configures and returns an ESLint configuration array for Vitest.
|
|
2187
2330
|
*
|
|
2188
2331
|
* @param [options] - The options to customize the configuration.
|
|
2332
|
+
* @param [options.files] - File globs to target (defaults to `GLOB_VITEST`).
|
|
2189
2333
|
* @param [options.overrides] - Custom rule overrides.
|
|
2190
2334
|
* @param [options.useJestDom] - Whether to use the `@testing-library/jest-dom` plugin.
|
|
2191
2335
|
* @param [options.useTestingLibrary] - Whether to use the `@testing-library/angular` plugin.
|
|
2336
|
+
* @param [options.e2eFolderPath] - The path to the e2e folder to ignore (this is only used internally by the `defineConfig` function, not by the user).
|
|
2192
2337
|
* @returns A promise that resolves to the ESLint configuration array.
|
|
2193
2338
|
* @example
|
|
2194
2339
|
* const config = await vitest({
|
|
2340
|
+
* files: ['**\/*.spec.ts'],
|
|
2195
2341
|
* overrides: {
|
|
2196
|
-
* '
|
|
2342
|
+
* 'vitest/prefer-lowercase-title': 'warn',
|
|
2197
2343
|
* },
|
|
2198
2344
|
* useJestDom: true,
|
|
2199
2345
|
* useTestingLibrary: false,
|
|
2200
2346
|
* });
|
|
2201
2347
|
*/
|
|
2202
2348
|
async function vitest(options = {}) {
|
|
2203
|
-
const { overrides = {}, useJestDom = isPackageExists("@testing-library/jest-dom"), useTestingLibrary = isPackageExists("@testing-library/angular") } = options;
|
|
2349
|
+
const { files = GLOB_VITEST, overrides = {}, useJestDom = isPackageExists("@testing-library/jest-dom"), useTestingLibrary = isPackageExists("@testing-library/angular"), enableVitestGlobals = true, e2eFolderPath } = options;
|
|
2204
2350
|
const [vitestPlugin, jestDomPlugin, testingLibraryPlugin] = await Promise.all([
|
|
2205
2351
|
interopDefault(import("@vitest/eslint-plugin")),
|
|
2206
2352
|
useJestDom ? interopDefault(import("eslint-plugin-jest-dom")) : Promise.resolve(void 0),
|
|
2207
2353
|
useTestingLibrary ? interopDefault(import("eslint-plugin-testing-library")) : Promise.resolve(void 0)
|
|
2208
2354
|
]);
|
|
2209
|
-
return
|
|
2355
|
+
return [{
|
|
2210
2356
|
name: "fabdeh/vitest/rules",
|
|
2211
2357
|
plugins: {
|
|
2212
2358
|
vitest: vitestPlugin,
|
|
@@ -2215,11 +2361,11 @@ async function vitest(options = {}) {
|
|
|
2215
2361
|
},
|
|
2216
2362
|
languageOptions: { globals: {
|
|
2217
2363
|
...globals.node,
|
|
2218
|
-
...globals
|
|
2219
|
-
...vitestPlugin.environments.env.globals
|
|
2364
|
+
...enableVitestGlobals ? vitestPlugin.environments.env.globals : {}
|
|
2220
2365
|
} },
|
|
2221
2366
|
settings: { vitest: { typecheck: true } },
|
|
2222
|
-
files
|
|
2367
|
+
files,
|
|
2368
|
+
...e2eFolderPath ? { ignores: [pathToGlobPattern()(e2eFolderPath)] } : {},
|
|
2223
2369
|
rules: {
|
|
2224
2370
|
...vitestPlugin.configs.recommended.rules,
|
|
2225
2371
|
...jestDomPlugin?.configs["flat/recommended"].rules,
|
|
@@ -2253,7 +2399,7 @@ async function vitest(options = {}) {
|
|
|
2253
2399
|
...getJsDocRules("off", true, "both"),
|
|
2254
2400
|
...overrides
|
|
2255
2401
|
}
|
|
2256
|
-
}
|
|
2402
|
+
}];
|
|
2257
2403
|
}
|
|
2258
2404
|
//#endregion
|
|
2259
2405
|
//#region src/configs/yaml.ts
|
|
@@ -2266,15 +2412,14 @@ async function vitest(options = {}) {
|
|
|
2266
2412
|
* @param options.stylistic - A boolean or object to specify stylistic rules. Defaults to `true`.
|
|
2267
2413
|
* @param options.stylistic.indent - The number of spaces for indentation or 'tab'. Defaults to `2`.
|
|
2268
2414
|
* @param options.stylistic.quotes - The type of quotes to use ('single', 'double', or 'backtick'). Defaults to `'single'`.
|
|
2269
|
-
* @returns A promise that resolves to a `
|
|
2415
|
+
* @returns A promise that resolves to a `TypedConfig[]` containing the ESLint configuration.
|
|
2270
2416
|
*/
|
|
2271
2417
|
async function yaml(options = {}) {
|
|
2272
2418
|
const { files = [GLOB_YAML], overrides = {}, stylistic = true } = options;
|
|
2273
2419
|
const { indent = 2, quotes = "single" } = typeof stylistic === "object" ? stylistic : {};
|
|
2274
|
-
|
|
2275
|
-
return tseslint.config({
|
|
2420
|
+
return [{
|
|
2276
2421
|
name: "fabdeh/yaml/setup",
|
|
2277
|
-
plugins: { yaml:
|
|
2422
|
+
plugins: { yaml: await interopDefault(import("eslint-plugin-yml")) }
|
|
2278
2423
|
}, {
|
|
2279
2424
|
name: "fabdeh/yaml/rules",
|
|
2280
2425
|
language: "yaml/yaml",
|
|
@@ -2306,7 +2451,7 @@ async function yaml(options = {}) {
|
|
|
2306
2451
|
} : {},
|
|
2307
2452
|
...overrides
|
|
2308
2453
|
}
|
|
2309
|
-
}
|
|
2454
|
+
}];
|
|
2310
2455
|
}
|
|
2311
2456
|
//#endregion
|
|
2312
2457
|
//#region src/shared/constants.ts
|
|
@@ -2316,6 +2461,7 @@ const NGRX_PACKAGES = [
|
|
|
2316
2461
|
"@ngrx/signals",
|
|
2317
2462
|
"@ngrx/operators"
|
|
2318
2463
|
];
|
|
2464
|
+
const PLAYWRIGHT_PACKAGES = ["@playwright/test", "playwright"];
|
|
2319
2465
|
const OPTIONS_SYMBOL = Symbol("options");
|
|
2320
2466
|
//#endregion
|
|
2321
2467
|
//#region src/factories/project-config.ts
|
|
@@ -2327,18 +2473,24 @@ const OPTIONS_SYMBOL = Symbol("options");
|
|
|
2327
2473
|
* @param baseConfig - The base configuration to extend from.
|
|
2328
2474
|
* @param options - Configuration options.
|
|
2329
2475
|
* @param userConfigs - Additional user configurations that can be awaited.
|
|
2330
|
-
* @returns
|
|
2476
|
+
* @returns The merged ESLint configurations.
|
|
2331
2477
|
* @example
|
|
2332
2478
|
* ```typescript
|
|
2479
|
+
* import { defineProjectConfig } from '@fabdeh/eslint-config';
|
|
2480
|
+
*
|
|
2333
2481
|
* import baseConfig from '../../eslint.base.js';
|
|
2334
2482
|
*
|
|
2335
|
-
*
|
|
2483
|
+
* export default defineProjectConfig(baseConfig, { vitest: true, typescript: { parserOptions: { project: './tsconfig.json' } } });
|
|
2336
2484
|
* ```
|
|
2337
2485
|
*/
|
|
2338
|
-
|
|
2339
|
-
const
|
|
2340
|
-
const workspaceOptions = resolvedBaseConfig[OPTIONS_SYMBOL];
|
|
2486
|
+
function defineProjectConfig(baseConfig, options = {}, ...userConfigs) {
|
|
2487
|
+
const workspaceOptions = baseConfig[OPTIONS_SYMBOL];
|
|
2341
2488
|
const { angular: enableAngular = isPackageExists("@angular/core"), jsdoc: enableJsdoc = options.type === "lib", ngrx: enableNgrx = NGRX_PACKAGES.some((p) => isPackageExists(p)), tailwindcss: enableTailwind = false, typescript: typescriptOptions, vitest: enableVitest = isPackageExists("vitest") } = options;
|
|
2489
|
+
let isInEditor = workspaceOptions.isInEditor;
|
|
2490
|
+
if (isInEditor === void 0) {
|
|
2491
|
+
isInEditor = isInEditorEnv();
|
|
2492
|
+
if (isInEditor) console.log("[@fabdeh/eslint-config] Detected running in editor, some rules are disabled.");
|
|
2493
|
+
}
|
|
2342
2494
|
if (enableNgrx && !enableAngular) throw new Error("NgRx rules can only be enabled if Angular rules are also enabled.");
|
|
2343
2495
|
const configs = [];
|
|
2344
2496
|
const stylisticOptions = workspaceOptions.stylistic === false ? false : typeof workspaceOptions.stylistic === "object" ? workspaceOptions.stylistic : {};
|
|
@@ -2354,10 +2506,6 @@ async function defineProjectConfig(baseConfig, options = {}, ...userConfigs) {
|
|
|
2354
2506
|
if (enableAngular) {
|
|
2355
2507
|
const angularOptions = resolveSubOptions(options, "angular");
|
|
2356
2508
|
configs.push(angular(angularOptions));
|
|
2357
|
-
if (workspaceOptions.formatters) {
|
|
2358
|
-
const htmlFormatters = resolvedBaseConfig.find((c) => c.name === "fabdeh/formatter/html");
|
|
2359
|
-
if (htmlFormatters) delete htmlFormatters.languageOptions;
|
|
2360
|
-
}
|
|
2361
2509
|
}
|
|
2362
2510
|
if (enableNgrx) {
|
|
2363
2511
|
const ngrxOptions = resolveSubOptions(options, "ngrx");
|
|
@@ -2378,7 +2526,10 @@ async function defineProjectConfig(baseConfig, options = {}, ...userConfigs) {
|
|
|
2378
2526
|
stylistic: stylisticOptions
|
|
2379
2527
|
}));
|
|
2380
2528
|
}
|
|
2381
|
-
|
|
2529
|
+
let composer = new FlatConfigComposer();
|
|
2530
|
+
composer = composer.append(baseConfig, ...configs, ...userConfigs);
|
|
2531
|
+
if (isInEditor) composer = composer.disableRulesFix(["prefer-const", "unused-imports/no-unused-imports"], { builtinRules: () => import("eslint/use-at-your-own-risk").then((m) => m.builtinRules) });
|
|
2532
|
+
return composer;
|
|
2382
2533
|
}
|
|
2383
2534
|
//#endregion
|
|
2384
2535
|
//#region src/factories/standard-config.ts
|
|
@@ -2388,26 +2539,36 @@ async function defineProjectConfig(baseConfig, options = {}, ...userConfigs) {
|
|
|
2388
2539
|
*
|
|
2389
2540
|
* @param options - Configuration options.
|
|
2390
2541
|
* @param userConfigs - Additional user configurations that can be awaited.
|
|
2391
|
-
* @returns
|
|
2542
|
+
* @returns The merged ESLint configurations.
|
|
2392
2543
|
* @example
|
|
2393
2544
|
* ```typescript
|
|
2394
|
-
*
|
|
2545
|
+
* import { defineConfig } from '@fabdeh/eslint-config';
|
|
2546
|
+
*
|
|
2547
|
+
* export default defineConfig({ vitest: true, typescript: { parserOptions: { project: './tsconfig.json' } } });
|
|
2395
2548
|
* ```
|
|
2396
2549
|
*/
|
|
2397
|
-
|
|
2398
|
-
const { angular: enableAngular = isPackageExists("@angular/core"), gitignore: enableGitignore = true, jsdoc: enableJsdoc = options.type === "lib", ngrx: enableNgrx = NGRX_PACKAGES.some((p) => isPackageExists(p)), pnpm: enableCatalogs =
|
|
2550
|
+
function defineConfig(options = {}, ...userConfigs) {
|
|
2551
|
+
const { angular: enableAngular = isPackageExists("@angular/core"), gitignore: enableGitignore = true, jsdoc: enableJsdoc = options.type === "lib", ngrx: enableNgrx = NGRX_PACKAGES.some((p) => isPackageExists(p)), playwright: enablePlaywright = PLAYWRIGHT_PACKAGES.some((p) => isPackageExists(p)), pnpm: enableCatalogs = !!findUpSync("pnpm-workspace.yaml"), regexp: enableRegexp = true, tailwindcss: enableTailwind = false, typescript: enableTypescript = isPackageExists("typescript"), unicorn: enableUnicorn = true, vitest: enableVitest = isPackageExists("vitest") } = options;
|
|
2552
|
+
let isInEditor = options.isInEditor;
|
|
2553
|
+
if (isInEditor === void 0) {
|
|
2554
|
+
isInEditor = isInEditorEnv();
|
|
2555
|
+
if (isInEditor) console.log("[@fabdeh/eslint-config] Detected running in editor, some rules are disabled.");
|
|
2556
|
+
}
|
|
2399
2557
|
if (enableNgrx && !enableAngular) throw new Error("NgRx rules can only be enabled if Angular rules are also enabled.");
|
|
2400
2558
|
const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
|
|
2401
2559
|
const configs = [];
|
|
2402
|
-
if (enableGitignore) if (typeof enableGitignore === "object") configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) =>
|
|
2560
|
+
if (enableGitignore) if (typeof enableGitignore === "object") configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => [r({
|
|
2403
2561
|
name: "fabdeh/gitignore",
|
|
2404
2562
|
...enableGitignore
|
|
2405
|
-
})))
|
|
2406
|
-
else configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) =>
|
|
2563
|
+
})]));
|
|
2564
|
+
else configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => [r({
|
|
2407
2565
|
name: "fabdeh/gitignore",
|
|
2408
2566
|
strict: true
|
|
2409
|
-
})))
|
|
2410
|
-
configs.push(ignores(options.ignores), javascript({
|
|
2567
|
+
})]));
|
|
2568
|
+
configs.push(ignores(options.ignores), javascript({
|
|
2569
|
+
isInEditor,
|
|
2570
|
+
overrides: options.javascript?.overrides
|
|
2571
|
+
}), comments(), node(), imports({ stylistic: stylisticOptions }), perfectionist());
|
|
2411
2572
|
if (enableJsdoc) configs.push(jsdoc({ stylistic: stylisticOptions }));
|
|
2412
2573
|
if (enableUnicorn) {
|
|
2413
2574
|
const unicornOptions = resolveSubOptions(options, "unicorn");
|
|
@@ -2438,9 +2599,21 @@ async function defineConfig(options = {}, ...userConfigs) {
|
|
|
2438
2599
|
useRelaxedNamingConventionForCamelAndPascalCases: typescriptOptions.useRelaxedNamingConventionForCamelAndPascalCases
|
|
2439
2600
|
}));
|
|
2440
2601
|
}
|
|
2602
|
+
let e2eFolderPath;
|
|
2603
|
+
if (enablePlaywright) {
|
|
2604
|
+
const playwrightOptions = resolveSubOptions(options, "playwright");
|
|
2605
|
+
e2eFolderPath = playwrightOptions.e2eFolderPath ?? getPlaywrightDirectory() ?? "e2e";
|
|
2606
|
+
configs.push(playwright({
|
|
2607
|
+
...playwrightOptions,
|
|
2608
|
+
e2eFolderPath
|
|
2609
|
+
}));
|
|
2610
|
+
}
|
|
2441
2611
|
if (enableVitest) {
|
|
2442
2612
|
const vitestOptions = resolveSubOptions(options, "vitest");
|
|
2443
|
-
configs.push(vitest(
|
|
2613
|
+
configs.push(vitest({
|
|
2614
|
+
...vitestOptions,
|
|
2615
|
+
e2eFolderPath
|
|
2616
|
+
}));
|
|
2444
2617
|
}
|
|
2445
2618
|
if (enableTailwind) {
|
|
2446
2619
|
const tailwindcssOptions = resolveSubOptions(options, "tailwindcss");
|
|
@@ -2456,7 +2629,15 @@ async function defineConfig(options = {}, ...userConfigs) {
|
|
|
2456
2629
|
stylistic: stylisticOptions
|
|
2457
2630
|
}), sortPackageJson(), sortTsConfig());
|
|
2458
2631
|
}
|
|
2459
|
-
if (enableCatalogs)
|
|
2632
|
+
if (enableCatalogs) {
|
|
2633
|
+
const pnpmOptions = resolveSubOptions(options, "pnpm");
|
|
2634
|
+
configs.push(pnpm({
|
|
2635
|
+
isInEditor,
|
|
2636
|
+
json: options.jsonc !== false,
|
|
2637
|
+
yaml: options.yaml !== false,
|
|
2638
|
+
...pnpmOptions
|
|
2639
|
+
}));
|
|
2640
|
+
}
|
|
2460
2641
|
if (options.yaml ?? true) {
|
|
2461
2642
|
const yamlOptions = resolveSubOptions(options, "yaml");
|
|
2462
2643
|
configs.push(yaml({
|
|
@@ -2475,8 +2656,10 @@ async function defineConfig(options = {}, ...userConfigs) {
|
|
|
2475
2656
|
const markdownOptions = resolveSubOptions(options, "markdown");
|
|
2476
2657
|
configs.push(markdown(markdownOptions));
|
|
2477
2658
|
}
|
|
2478
|
-
|
|
2479
|
-
|
|
2659
|
+
let composer = new FlatConfigComposer();
|
|
2660
|
+
composer = composer.append(...configs, ...userConfigs);
|
|
2661
|
+
if (isInEditor) composer = composer.disableRulesFix(["prefer-const", "unused-imports/no-unused-imports"], { builtinRules: () => import("eslint/use-at-your-own-risk").then((m) => m.builtinRules) });
|
|
2662
|
+
return composer;
|
|
2480
2663
|
}
|
|
2481
2664
|
//#endregion
|
|
2482
2665
|
//#region src/factories/workspace-config.ts
|
|
@@ -2487,25 +2670,35 @@ async function defineConfig(options = {}, ...userConfigs) {
|
|
|
2487
2670
|
*
|
|
2488
2671
|
* @param options - Configuration options.
|
|
2489
2672
|
* @param userConfigs - Additional user configurations that can be awaited.
|
|
2490
|
-
* @returns
|
|
2673
|
+
* @returns The merged ESLint configurations.
|
|
2491
2674
|
* @example
|
|
2492
2675
|
* ```typescript
|
|
2493
|
-
*
|
|
2676
|
+
* import { defineWorkspaceConfig } from '@fabdeh/eslint-config';
|
|
2677
|
+
*
|
|
2678
|
+
* export default defineWorkspaceConfig({ typescript: { parserOptions: { project: './tsconfig.json' } } });
|
|
2494
2679
|
* ```
|
|
2495
2680
|
*/
|
|
2496
|
-
|
|
2497
|
-
const { gitignore: enableGitignore = true, pnpm: enableCatalogs =
|
|
2681
|
+
function defineWorkspaceConfig(options = {}, ...userConfigs) {
|
|
2682
|
+
const { gitignore: enableGitignore = true, pnpm: enableCatalogs = !!findUpSync("pnpm-workspace.yaml"), regexp: enableRegexp = true, typescript: enableTypescript = isPackageExists("typescript"), unicorn: enableUnicorn = true } = options;
|
|
2683
|
+
let isInEditor = options.isInEditor;
|
|
2684
|
+
if (isInEditor === void 0) {
|
|
2685
|
+
isInEditor = isInEditorEnv();
|
|
2686
|
+
if (isInEditor) console.log("[@fabdeh/eslint-config] Detected running in editor, some rules are disabled.");
|
|
2687
|
+
}
|
|
2498
2688
|
const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
|
|
2499
2689
|
const configs = [];
|
|
2500
|
-
if (enableGitignore) if (typeof enableGitignore === "object") configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) =>
|
|
2690
|
+
if (enableGitignore) if (typeof enableGitignore === "object") configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => [r({
|
|
2501
2691
|
name: "fabdeh/gitignore",
|
|
2502
2692
|
...enableGitignore
|
|
2503
|
-
})))
|
|
2504
|
-
else configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) =>
|
|
2693
|
+
})]));
|
|
2694
|
+
else configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => [r({
|
|
2505
2695
|
name: "fabdeh/gitignore",
|
|
2506
2696
|
strict: true
|
|
2507
|
-
})))
|
|
2508
|
-
configs.push(ignores(options.ignores, "workspace"), javascript({
|
|
2697
|
+
})]));
|
|
2698
|
+
configs.push(ignores(options.ignores, "workspace"), javascript({
|
|
2699
|
+
isInEditor,
|
|
2700
|
+
overrides: options.javascript?.overrides
|
|
2701
|
+
}), comments(), node(), imports({ stylistic: stylisticOptions }), perfectionist());
|
|
2509
2702
|
if (enableUnicorn) {
|
|
2510
2703
|
const unicornOptions = resolveSubOptions(options, "unicorn");
|
|
2511
2704
|
configs.push(unicorn(unicornOptions));
|
|
@@ -2530,7 +2723,15 @@ async function defineWorkspaceConfig(options = {}, ...userConfigs) {
|
|
|
2530
2723
|
stylistic: stylisticOptions
|
|
2531
2724
|
}), sortPackageJson(), sortTsConfig());
|
|
2532
2725
|
}
|
|
2533
|
-
if (enableCatalogs)
|
|
2726
|
+
if (enableCatalogs) {
|
|
2727
|
+
const pnpmOptions = resolveSubOptions(options, "pnpm");
|
|
2728
|
+
configs.push(pnpm({
|
|
2729
|
+
isInEditor,
|
|
2730
|
+
json: options.jsonc !== false,
|
|
2731
|
+
yaml: options.yaml !== false,
|
|
2732
|
+
...pnpmOptions
|
|
2733
|
+
}));
|
|
2734
|
+
}
|
|
2534
2735
|
if (options.yaml ?? true) {
|
|
2535
2736
|
const yamlOptions = resolveSubOptions(options, "yaml");
|
|
2536
2737
|
configs.push(yaml({
|
|
@@ -2549,10 +2750,12 @@ async function defineWorkspaceConfig(options = {}, ...userConfigs) {
|
|
|
2549
2750
|
const markdownOptions = resolveSubOptions(options, "markdown");
|
|
2550
2751
|
configs.push(markdown(markdownOptions));
|
|
2551
2752
|
}
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2753
|
+
let composer = new FlatConfigComposer();
|
|
2754
|
+
composer = composer.append(...configs, ...userConfigs);
|
|
2755
|
+
if (isInEditor) composer = composer.disableRulesFix(["prefer-const", "unused-imports/no-unused-imports"], { builtinRules: () => import("eslint/use-at-your-own-risk").then((m) => m.builtinRules) });
|
|
2756
|
+
const composerWithOptions = composer;
|
|
2757
|
+
composerWithOptions[OPTIONS_SYMBOL] = options;
|
|
2758
|
+
return composerWithOptions;
|
|
2556
2759
|
}
|
|
2557
2760
|
//#endregion
|
|
2558
|
-
export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, defineConfig, defineProjectConfig, defineWorkspaceConfig, ensurePackages,
|
|
2761
|
+
export { CONFIG_PRESET_FULL_OFF, CONFIG_PRESET_FULL_ON, GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, convertPathToPosix, defineConfig, defineProjectConfig, defineWorkspaceConfig, ensurePackages, getPlaywrightDirectory, getTsConfigFileName, getWorkspaceRoot, ignores, imports, interopDefault, isDirectory, isInEditorEnv, isInGitHooksOrLintStaged, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, node, pathToGlobPattern, perfectionist, playwright, pnpm, regexp, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
|