@fabdeh/eslint-config 0.7.1 → 0.8.0-beta.2

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/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import perfectionistPlugin from "eslint-plugin-perfectionist";
17
17
  import { configs } from "eslint-plugin-regexp";
18
18
  import unicornPlugin from "eslint-plugin-unicorn";
19
19
 
20
- //#region src/globs.ts
20
+ //#region src/shared/globs.ts
21
21
  /**
22
22
  * A glob pattern that matches the extension of JavaScript and TypeScript source files.
23
23
  */
@@ -150,7 +150,7 @@ const GLOB_EXCLUDE = [
150
150
  ];
151
151
 
152
152
  //#endregion
153
- //#region src/utils.ts
153
+ //#region src/shared/utils.ts
154
154
  const SCOPE_URL = import.meta.dirname;
155
155
  const IS_CWD_IN_SCOPE = isPackageExists("@fabdeh/eslint-config");
156
156
  /**
@@ -195,12 +195,11 @@ function fileExists(path) {
195
195
  function getWorkspaceRoot(dir, candidateRoot) {
196
196
  if (process.env.NX_WORKSPACE_ROOT) return process.env.NX_WORKSPACE_ROOT;
197
197
  if (dirname(dir) === dir) return candidateRoot;
198
- const matches = [
198
+ if ([
199
199
  join(dir, "nx.json"),
200
200
  join(dir, "nx"),
201
201
  join(dir, "nx.bat")
202
- ];
203
- if (matches.some((x) => fileExists(x))) return dir;
202
+ ].some((x) => fileExists(x))) return dir;
204
203
  else if (fileExists(join(dir, "node_modules", "nx", "package.json"))) return getWorkspaceRoot(dirname(dir), dir);
205
204
  else return getWorkspaceRoot(dirname(dir), candidateRoot);
206
205
  }
@@ -241,9 +240,7 @@ async function ensurePackages(packages) {
241
240
  if (process.env.CI || !process.stdout.isTTY || !IS_CWD_IN_SCOPE) return;
242
241
  const nonExistingPackages = packages.filter((i) => i && !isPackageInScope(i));
243
242
  if (nonExistingPackages.length === 0) return;
244
- const p = await import("@clack/prompts");
245
- const result = await p.confirm({ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?` });
246
- if (result) await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
243
+ 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 }));
247
244
  }
248
245
  /**
249
246
  * Search for the nearest package.json file and return the `name` property value.
@@ -254,8 +251,7 @@ async function ensurePackages(packages) {
254
251
  async function findNearestPackageJsonName(directoryPath = resolve()) {
255
252
  try {
256
253
  const packageJsonPath = join(directoryPath, "package.json");
257
- const packageJsonData = JSON.parse(await readFile(packageJsonPath, "utf8"));
258
- return packageJsonData.name;
254
+ return JSON.parse(await readFile(packageJsonPath, "utf8")).name;
259
255
  } catch {
260
256
  const parentDir = dirname(directoryPath);
261
257
  if (directoryPath === parentDir) throw new Error("No package.json file found.");
@@ -832,7 +828,7 @@ function javascript(options = {}) {
832
828
  * Get the JSDoc rules based on specific parameters.
833
829
  *
834
830
  * @param level - The level of (mostly) all rules.
835
- * @param stylistic - Does the stylistic rules be included.
831
+ * @param stylistic - Should the stylistic rules be included.
836
832
  * @param mode - To get on JS or TS rules or both.
837
833
  * @returns The JSDoc eslint rules configured with the requested level.
838
834
  */
@@ -842,7 +838,7 @@ function getJsDocRules(level, stylistic$1, mode) {
842
838
  "jsdoc/check-access": level,
843
839
  "jsdoc/check-param-names": level,
844
840
  "jsdoc/check-property-names": level,
845
- "jsdoc/check-tag-names": level,
841
+ "jsdoc/check-tag-names": [level, { definedTags: ["experimental"] }],
846
842
  "jsdoc/check-types": level,
847
843
  "jsdoc/check-values": level,
848
844
  "jsdoc/empty-tags": level,
@@ -879,7 +875,10 @@ function getJsDocRules(level, stylistic$1, mode) {
879
875
  } : {}
880
876
  } : {},
881
877
  ...mode === "both" || mode === "tsOnly" ? {
882
- "jsdoc/check-tag-names": [level, { typed: true }],
878
+ "jsdoc/check-tag-names": [level, {
879
+ typed: true,
880
+ definedTags: ["experimental"]
881
+ }],
883
882
  "jsdoc/no-types": level,
884
883
  "jsdoc/no-undefined-types": "off",
885
884
  "jsdoc/require-param-type": "off",
@@ -1019,25 +1018,6 @@ async function jsonc(options = {}) {
1019
1018
  async function markdown(options = {}) {
1020
1019
  const { files = [GLOB_MARKDOWN], overrides = {} } = options;
1021
1020
  const markdownPlugin = await interopDefault(import("@eslint/markdown"));
1022
- const parserPlain = {
1023
- meta: { name: "parser-plain" },
1024
- parseForESLint: (code) => ({
1025
- ast: {
1026
- body: [],
1027
- comments: [],
1028
- loc: {
1029
- end: code.length,
1030
- start: 0
1031
- },
1032
- range: [0, code.length],
1033
- tokens: [],
1034
- type: "Program"
1035
- },
1036
- scopeManager: null,
1037
- services: { isPlain: true },
1038
- visitorKeys: { Program: [] }
1039
- })
1040
- };
1041
1021
  return tseslint.config({
1042
1022
  name: "fabdeh/markdown/setup",
1043
1023
  plugins: { markdown: markdownPlugin }
@@ -1049,7 +1029,25 @@ async function markdown(options = {}) {
1049
1029
  }, {
1050
1030
  name: "fabdeh/markdown/parser",
1051
1031
  files,
1052
- languageOptions: { parser: parserPlain }
1032
+ languageOptions: { parser: {
1033
+ meta: { name: "parser-plain" },
1034
+ parseForESLint: (code) => ({
1035
+ ast: {
1036
+ body: [],
1037
+ comments: [],
1038
+ loc: {
1039
+ end: code.length,
1040
+ start: 0
1041
+ },
1042
+ range: [0, code.length],
1043
+ tokens: [],
1044
+ type: "Program"
1045
+ },
1046
+ scopeManager: null,
1047
+ services: { isPlain: true },
1048
+ visitorKeys: { Program: [] }
1049
+ })
1050
+ } }
1053
1051
  }, {
1054
1052
  name: "fabdeh/markdown/disables",
1055
1053
  languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
@@ -1893,10 +1891,11 @@ const MEMBER_ORDERING_OPTIONS = { default: [
1893
1891
  * @param options.stylistic - A boolean indicating whether stylistic rules should be included. Defaults to true.
1894
1892
  * @param options.parserOptions - Options for the TypeScript parser.
1895
1893
  * @param options.overrides - Additional rule overrides.
1894
+ * @param isWorkspaceProject - A boolean indicating whether the project is a workspace project. Defaults to false.
1896
1895
  * @returns A TypedConfigArray containing the TypeScript ESLint configuration.
1897
1896
  */
1898
- async function typescript(options = {}) {
1899
- const { stylistic: stylistic$1 = true, parserOptions = {}, overrides = {}, enableErasableSyntaxOnly = false, useRelaxedNamingConventionForCamelAndPascalCases = false, type = "app" } = options;
1897
+ async function typescript(options = {}, isWorkspaceProject = false) {
1898
+ const { enableErasableSyntaxOnly = false, overrides = {}, parserOptions = {}, stylistic: stylistic$1 = true, type = "app", useRelaxedNamingConventionForCamelAndPascalCases = false } = options;
1900
1899
  let erasableSyntaxOnlyPlugin;
1901
1900
  let erasableSyntaxOnlyRules;
1902
1901
  if (enableErasableSyntaxOnly) {
@@ -1908,7 +1907,7 @@ async function typescript(options = {}) {
1908
1907
  const tsconfigRootDir = getWorkspaceRoot(process.cwd(), process.cwd());
1909
1908
  const defaultProject = getTsConfigFileName(tsconfigRootDir);
1910
1909
  return tseslint.config({
1911
- name: "fabdeh/typescript/setup",
1910
+ name: `fabdeh/${type}/typescript/setup`,
1912
1911
  files: [GLOB_TS],
1913
1912
  ignores: [`${GLOB_MARKDOWN}/**`],
1914
1913
  languageOptions: {
@@ -1923,8 +1922,21 @@ async function typescript(options = {}) {
1923
1922
  ...parserOptions
1924
1923
  }
1925
1924
  }
1926
- }, {
1927
- name: "fabdeh/typescript/rules",
1925
+ }, isWorkspaceProject ? {
1926
+ name: `fabdeh/${type}/typescript/rules`,
1927
+ files: [GLOB_TS],
1928
+ ignores: [`${GLOB_MARKDOWN}/**`],
1929
+ plugins: { "@typescript-eslint": tseslint.plugin },
1930
+ rules: {
1931
+ ...type === "lib" ? { "@typescript-eslint/explicit-function-return-type": ["error", {
1932
+ allowExpressions: true,
1933
+ allowIIFEs: true
1934
+ }] } : {},
1935
+ "@typescript-eslint/explicit-module-boundary-types": "error",
1936
+ ...overrides
1937
+ }
1938
+ } : {
1939
+ name: `fabdeh/${type}/typescript/rules`,
1928
1940
  files: [GLOB_TS],
1929
1941
  ignores: [`${GLOB_MARKDOWN}/**`],
1930
1942
  plugins: {
@@ -1953,8 +1965,9 @@ async function typescript(options = {}) {
1953
1965
  ...type === "lib" ? { "@typescript-eslint/explicit-function-return-type": ["error", {
1954
1966
  allowExpressions: true,
1955
1967
  allowIIFEs: true
1956
- }] } : { "@typescript-eslint/explicit-module-boundary-types": "error" },
1968
+ }] } : {},
1957
1969
  "@typescript-eslint/explicit-member-accessibility": ["error", { accessibility: "no-public" }],
1970
+ ...type === "workspace" ? {} : { "@typescript-eslint/explicit-module-boundary-types": "error" },
1958
1971
  "@typescript-eslint/member-ordering": ["error", MEMBER_ORDERING_OPTIONS],
1959
1972
  "@typescript-eslint/method-signature-style": "error",
1960
1973
  "@typescript-eslint/naming-convention": ["error", ...namingConvention(!useRelaxedNamingConventionForCamelAndPascalCases)],
@@ -2241,26 +2254,89 @@ async function yaml(options = {}) {
2241
2254
  }
2242
2255
 
2243
2256
  //#endregion
2244
- //#region src/types.ts
2245
- const OPTIONS_SYMBOL = Symbol("options");
2246
-
2247
- //#endregion
2248
- //#region src/factory.ts
2257
+ //#region src/shared/constants.ts
2249
2258
  const NGRX_PACKAGES = [
2250
2259
  "@ngrx/store",
2251
2260
  "@ngrx/effects",
2252
2261
  "@ngrx/signals",
2253
2262
  "@ngrx/operators"
2254
2263
  ];
2264
+ const OPTIONS_SYMBOL = Symbol("options");
2265
+
2266
+ //#endregion
2267
+ //#region src/factories/project-config.ts
2268
+ /**
2269
+ * Creates an ESLint configuration array based on the provided base configuration, options and user configurations.
2270
+ * This function is similar to `defineConfig`, but it is designed for use in a project of a workspace environment.
2271
+ * It requires a base configuration that is already defined in the root of the workspace via the `defineWorkspaceConfig` function.
2272
+ *
2273
+ * @param baseConfig - The base configuration to extend from.
2274
+ * @param options - Configuration options.
2275
+ * @param userConfigs - Additional user configurations that can be awaited.
2276
+ * @returns A promise that resolves to a `TypedConfigArray`.
2277
+ * @example
2278
+ * ```typescript
2279
+ * import baseConfig from '../../eslint.base.js';
2280
+ *
2281
+ * const config = await defineProjectConfig(baseConfig, { vitest: true, typescript: { parserOptions: { project: './tsconfig.json' } } });
2282
+ * ```
2283
+ */
2284
+ async function defineProjectConfig(baseConfig, options = {}, ...userConfigs) {
2285
+ const resolvedBaseConfig = await baseConfig;
2286
+ const workspaceOptions = resolvedBaseConfig[OPTIONS_SYMBOL];
2287
+ const { angular: enableAngular = isPackageExists("@angular/core"), jsdoc: enableJsdoc = true, ngrx: enableNgrx = NGRX_PACKAGES.some((p) => isPackageExists(p)), tailwindcss: enableTailwind = false, typescript: typescriptOptions, vitest: enableVitest = isPackageExists("vitest") } = options;
2288
+ if (enableNgrx && !enableAngular) throw new Error("NgRx rules can only be enabled if Angular rules are also enabled.");
2289
+ const configs$1 = [];
2290
+ if (enableJsdoc) {
2291
+ const stylisticOptions = workspaceOptions.stylistic === false ? false : typeof workspaceOptions.stylistic === "object" ? workspaceOptions.stylistic : {};
2292
+ configs$1.push(jsdoc({ stylistic: stylisticOptions }));
2293
+ }
2294
+ if (typescriptOptions) {
2295
+ if (!workspaceOptions.typescript) throw new Error("Project-specific TypeScript configuration requires a base configuration with TypeScript support.");
2296
+ configs$1.push(typescript({
2297
+ ...typescriptOptions,
2298
+ type: options.type
2299
+ }, true));
2300
+ }
2301
+ if (enableAngular) {
2302
+ const angularOptions = resolveSubOptions(options, "angular");
2303
+ configs$1.push(angular(angularOptions));
2304
+ if (workspaceOptions.formatters) {
2305
+ const htmlFormatters = resolvedBaseConfig.find((c) => c.name === "fabdeh/formatter/html");
2306
+ if (htmlFormatters) delete htmlFormatters.languageOptions;
2307
+ }
2308
+ }
2309
+ if (enableNgrx) {
2310
+ const ngrxOptions = resolveSubOptions(options, "ngrx");
2311
+ const typescriptOptions$1 = resolveSubOptions(workspaceOptions, "typescript");
2312
+ configs$1.push(ngrx({
2313
+ ...ngrxOptions,
2314
+ useRelaxedNamingConventionForCamelAndPascalCases: typescriptOptions$1.useRelaxedNamingConventionForCamelAndPascalCases
2315
+ }));
2316
+ }
2317
+ if (enableVitest) {
2318
+ const vitestOptions = resolveSubOptions(options, "vitest");
2319
+ configs$1.push(vitest(vitestOptions));
2320
+ }
2321
+ if (enableTailwind) {
2322
+ const tailwindcssOptions = resolveSubOptions(options, "tailwindcss");
2323
+ configs$1.push(tailwindcss(tailwindcssOptions));
2324
+ }
2325
+ return tseslint.config(...resolvedBaseConfig, ...await Promise.all(configs$1), ...await Promise.all(userConfigs));
2326
+ }
2327
+
2328
+ //#endregion
2329
+ //#region src/factories/standard-config.ts
2255
2330
  /**
2256
2331
  * Creates an ESLint configuration array based on the provided options and user configurations.
2332
+ * Additionally, it will automatically detect the presence of certain packages and enable corresponding rules.
2257
2333
  *
2258
- * @param options - Configuration options that extend `ConfigWithExtends` and `CreateConfigOptions`.
2334
+ * @param options - Configuration options.
2259
2335
  * @param userConfigs - Additional user configurations that can be awaited.
2260
- * @returns A promise that resolves to a `ConfigArray`.
2336
+ * @returns A promise that resolves to a `ConfigArrayWithOptions`.
2261
2337
  * @example
2262
2338
  * ```typescript
2263
- * const config = await createConfig({ vitest: true, typescript: { parserOptions: { project: './tsconfig.json' } } });
2339
+ * const config = await defineConfig({ vitest: true, typescript: { parserOptions: { project: './tsconfig.json' } } });
2264
2340
  * ```
2265
2341
  */
2266
2342
  async function defineConfig(options = {}, ...userConfigs) {
@@ -2342,10 +2418,85 @@ async function defineConfig(options = {}, ...userConfigs) {
2342
2418
  configs$1.push(markdown(markdownOptions));
2343
2419
  }
2344
2420
  if (options.formatters) configs$1.push(formatters(options.formatters, typeof stylisticOptions === "boolean" ? {} : stylisticOptions, Boolean(enableAngular)));
2345
- const config = tseslint.config(...await Promise.all(configs$1), ...await Promise.all(userConfigs));
2346
- config[OPTIONS_SYMBOL] = options;
2347
- return config;
2421
+ return tseslint.config(...await Promise.all(configs$1), ...await Promise.all(userConfigs));
2422
+ }
2423
+
2424
+ //#endregion
2425
+ //#region src/factories/workspace-config.ts
2426
+ /**
2427
+ * Creates an ESLint configuration array based on the provided options and user configurations.
2428
+ * This function is similar to `defineConfig`, but it is designed for use in the root of a workspace environment.
2429
+ * Contrary to `defineConfig`, it will not automatically detect the presence of certain packages and will not enable corresponding rules.
2430
+ *
2431
+ * @param options - Configuration options.
2432
+ * @param userConfigs - Additional user configurations that can be awaited.
2433
+ * @returns A promise that resolves to a `ConfigArrayWithOptions`.
2434
+ * @example
2435
+ * ```typescript
2436
+ * const config = await defineWorkspaceConfig({ vitest: true, typescript: { parserOptions: { project: './tsconfig.json' } } });
2437
+ * ```
2438
+ */
2439
+ async function defineWorkspaceConfig(options = {}, ...userConfigs) {
2440
+ const { gitignore: enableGitignore = true, pnpm: enableCatalogs = false, regexp: enableRegexp = true, typescript: enableTypescript = isPackageExists("typescript"), unicorn: enableUnicorn = true } = options;
2441
+ const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
2442
+ const configs$1 = [];
2443
+ if (enableGitignore) if (typeof enableGitignore === "object") configs$1.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => tseslint.config(r({
2444
+ name: "fabdeh/gitignore",
2445
+ ...enableGitignore
2446
+ }))));
2447
+ else configs$1.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => tseslint.config(r({
2448
+ name: "fabdeh/gitignore",
2449
+ strict: true
2450
+ }))));
2451
+ configs$1.push(ignores(options.ignores), javascript({ overrides: options.javascript?.overrides }), comments(), node(), imports({ stylistic: stylisticOptions }), perfectionist());
2452
+ if (enableUnicorn) {
2453
+ const unicornOptions = resolveSubOptions(options, "unicorn");
2454
+ configs$1.push(unicorn(unicornOptions));
2455
+ }
2456
+ if (enableTypescript) {
2457
+ const typescriptOptions = resolveSubOptions(options, "typescript");
2458
+ configs$1.push(typescript({
2459
+ ...typescriptOptions,
2460
+ stylistic: stylisticOptions,
2461
+ type: "workspace"
2462
+ }));
2463
+ }
2464
+ if (stylisticOptions) configs$1.push(stylistic({ stylistic: stylisticOptions }));
2465
+ if (enableRegexp) {
2466
+ const regexpOptions = resolveSubOptions(options, "regexp");
2467
+ configs$1.push(regexp(regexpOptions));
2468
+ }
2469
+ if (options.jsonc ?? true) {
2470
+ const jsoncOptions = resolveSubOptions(options, "jsonc");
2471
+ configs$1.push(jsonc({
2472
+ ...jsoncOptions,
2473
+ stylistic: stylisticOptions
2474
+ }), sortPackageJson(), sortTsConfig());
2475
+ }
2476
+ if (enableCatalogs) configs$1.push(pnpm());
2477
+ if (options.yaml ?? true) {
2478
+ const yamlOptions = resolveSubOptions(options, "yaml");
2479
+ configs$1.push(yaml({
2480
+ ...yamlOptions,
2481
+ stylistic: stylisticOptions
2482
+ }));
2483
+ }
2484
+ if (options.toml ?? true) {
2485
+ const tomlOptions = resolveSubOptions(options, "toml");
2486
+ configs$1.push(toml({
2487
+ ...tomlOptions,
2488
+ stylistic: stylisticOptions
2489
+ }));
2490
+ }
2491
+ if (options.markdown ?? true) {
2492
+ const markdownOptions = resolveSubOptions(options, "markdown");
2493
+ configs$1.push(markdown(markdownOptions));
2494
+ }
2495
+ if (options.formatters) configs$1.push(formatters(options.formatters, typeof stylisticOptions === "boolean" ? {} : stylisticOptions, false));
2496
+ const eslintConfigWithOptions = tseslint.config(...await Promise.all(configs$1), ...await Promise.all(userConfigs));
2497
+ eslintConfigWithOptions[OPTIONS_SYMBOL] = options;
2498
+ return eslintConfigWithOptions;
2348
2499
  }
2349
2500
 
2350
2501
  //#endregion
2351
- export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, defineConfig, ensurePackages, findNearestPackageJsonName, formatters, getTsConfigFileName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, node, perfectionist, pnpm, regexp, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
2502
+ export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, defineConfig, defineProjectConfig, defineWorkspaceConfig, ensurePackages, findNearestPackageJsonName, formatters, getTsConfigFileName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, node, perfectionist, pnpm, regexp, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fabdeh/eslint-config",
3
3
  "type": "module",
4
- "version": "0.7.1",
4
+ "version": "0.8.0-beta.2",
5
5
  "description": "My personal eslint config preset",
6
6
  "author": {
7
7
  "name": "Fabien Dehopré",
@@ -40,10 +40,10 @@
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@prettier/plugin-xml": "^3.4.2",
43
- "eslint": "^9.33.0",
44
- "eslint-plugin-better-tailwindcss": "^3.7.4",
43
+ "eslint": "^9.36.0",
44
+ "eslint-plugin-better-tailwindcss": "^3.7.9",
45
45
  "eslint-plugin-erasable-syntax-only": "^0.3.1",
46
- "eslint-plugin-format": "^1.0.1",
46
+ "eslint-plugin-format": "^1.0.2",
47
47
  "prettier-plugin-slidev": "^1.0.5"
48
48
  },
49
49
  "peerDependenciesMeta": {
@@ -67,76 +67,79 @@
67
67
  "@antfu/install-pkg": "^1.1.0",
68
68
  "@clack/prompts": "^0.11.0",
69
69
  "@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
70
- "@eslint/js": "^9.33.0",
71
- "@eslint/markdown": "^7.1.0",
72
- "@ngrx/eslint-plugin": "^20.0.0",
73
- "@stylistic/eslint-plugin": "^5.2.3",
74
- "@typescript-eslint/eslint-plugin": "^8.39.0",
75
- "@typescript-eslint/parser": "^8.39.0",
76
- "@typescript-eslint/utils": "^8.39.0",
77
- "@vitest/eslint-plugin": "^1.3.4",
78
- "angular-eslint": "^20.1.1",
70
+ "@eslint/js": "^9.36.0",
71
+ "@eslint/markdown": "^7.3.0",
72
+ "@ngrx/eslint-plugin": "^20.0.1",
73
+ "@stylistic/eslint-plugin": "^5.4.0",
74
+ "@typescript-eslint/eslint-plugin": "^8.44.1",
75
+ "@typescript-eslint/parser": "^8.44.1",
76
+ "@typescript-eslint/utils": "^8.44.1",
77
+ "@vitest/eslint-plugin": "^1.3.13",
78
+ "angular-eslint": "^20.3.0",
79
79
  "eslint-config-flat-gitignore": "^2.1.0",
80
- "eslint-flat-config-utils": "^2.1.1",
80
+ "eslint-flat-config-utils": "^2.1.4",
81
81
  "eslint-merge-processors": "^2.0.0",
82
82
  "eslint-plugin-import-x": "^4.16.1",
83
83
  "eslint-plugin-jest-dom": "^5.5.0",
84
- "eslint-plugin-jsdoc": "^52.0.4",
84
+ "eslint-plugin-jsdoc": "^54.7.0",
85
85
  "eslint-plugin-jsonc": "^2.20.1",
86
- "eslint-plugin-n": "^17.21.3",
86
+ "eslint-plugin-n": "^17.23.1",
87
87
  "eslint-plugin-perfectionist": "^4.15.0",
88
- "eslint-plugin-pnpm": "^1.1.0",
89
- "eslint-plugin-prefer-arrow-functions": "^3.6.2",
88
+ "eslint-plugin-pnpm": "^1.1.2",
89
+ "eslint-plugin-prefer-arrow-functions": "^3.8.1",
90
90
  "eslint-plugin-regexp": "^2.10.0",
91
- "eslint-plugin-testing-library": "^7.6.3",
91
+ "eslint-plugin-testing-library": "^7.10.0",
92
92
  "eslint-plugin-toml": "^0.12.0",
93
93
  "eslint-plugin-unicorn": "^60.0.0",
94
- "eslint-plugin-unused-imports": "^4.1.4",
94
+ "eslint-plugin-unused-imports": "^4.2.0",
95
95
  "eslint-plugin-yml": "^1.18.0",
96
- "globals": "^16.3.0",
97
- "jsonc-eslint-parser": "^2.4.0",
98
- "local-pkg": "^1.1.1",
96
+ "globals": "^16.4.0",
97
+ "jsonc-eslint-parser": "^2.4.1",
98
+ "local-pkg": "^1.1.2",
99
99
  "toml-eslint-parser": "^0.10.0",
100
- "typescript-eslint": "^8.39.0",
100
+ "typescript-eslint": "^8.44.1",
101
101
  "yaml-eslint-parser": "^1.3.0"
102
102
  },
103
103
  "devDependencies": {
104
- "@angular/core": "^20.1.6",
104
+ "@angular/core": "^20.3.2",
105
105
  "@arethetypeswrong/cli": "^0.18.2",
106
106
  "@commitlint/cli": "^19.8.1",
107
107
  "@commitlint/config-conventional": "^19.8.1",
108
108
  "@commitlint/cz-commitlint": "^19.8.1",
109
- "@ngrx/effects": "^20.0.0",
110
- "@ngrx/operators": "^20.0.0",
111
- "@ngrx/signals": "^20.0.0",
112
- "@ngrx/store": "^20.0.0",
109
+ "@commitlint/lint": "^19.8.1",
110
+ "@commitlint/load": "^19.8.1",
111
+ "@ngrx/effects": "^20.0.1",
112
+ "@ngrx/operators": "^20.0.1",
113
+ "@ngrx/signals": "^20.0.1",
114
+ "@ngrx/store": "^20.0.1",
113
115
  "@prettier/plugin-xml": "^3.4.2",
114
116
  "@testing-library/angular": "^18.0.0",
115
- "@testing-library/jest-dom": "^6.6.4",
117
+ "@testing-library/jest-dom": "^6.8.0",
116
118
  "@types/fs-extra": "^11.0.4",
117
- "@types/node": "^22.17.1",
118
- "bumpp": "^10.2.2",
119
+ "@types/node": "^22.18.6",
120
+ "@vitest/coverage-v8": "^3.2.4",
121
+ "bumpp": "^10.2.3",
119
122
  "changelogithub": "^13.16.0",
120
123
  "commitizen": "^4.3.1",
121
- "eslint": "^9.33.0",
122
- "eslint-plugin-better-tailwindcss": "^3.7.4",
124
+ "eslint": "^9.36.0",
125
+ "eslint-plugin-better-tailwindcss": "^3.7.9",
123
126
  "eslint-plugin-erasable-syntax-only": "^0.3.1",
124
- "eslint-plugin-format": "^1.0.1",
127
+ "eslint-plugin-format": "^1.0.2",
125
128
  "eslint-typegen": "^2.3.0",
126
129
  "execa": "^9.6.0",
127
130
  "fast-glob": "^3.3.3",
128
- "fs-extra": "^11.3.1",
131
+ "fs-extra": "^11.3.2",
129
132
  "is-ci": "^4.1.0",
130
- "jiti": "^2.5.1",
133
+ "jiti": "^2.6.0",
131
134
  "nano-staged": "^0.8.0",
132
135
  "prettier-plugin-slidev": "^1.0.5",
133
136
  "simple-git-hooks": "^2.13.1",
134
- "tailwindcss": "^4.1.11",
135
- "tsdown": "^0.14.1",
136
- "tsx": "^4.20.3",
137
+ "tailwindcss": "^4.1.13",
138
+ "tsdown": "^0.14.2",
139
+ "tsx": "^4.20.6",
137
140
  "typescript": "~5.8.3",
138
141
  "vitest": "^3.2.4",
139
- "@fabdeh/eslint-config": "0.7.1"
142
+ "@fabdeh/eslint-config": "0.8.0-beta.2"
140
143
  },
141
144
  "resolutions": {
142
145
  "eslint": "catalog:peer"
@@ -163,8 +166,12 @@
163
166
  "commit": "git-cz",
164
167
  "lint": "pnpm build && eslint . --fix",
165
168
  "lint:ci": "eslint . --quiet",
166
- "release": "bumpp && pnpm publish",
169
+ "release": "bumpp",
167
170
  "typecheck": "tsc --noEmit",
168
- "gen": "tsx scripts/typegen.ts"
171
+ "gen": "tsx scripts/typegen.ts",
172
+ "validate-pr-title": "tsx scripts/validate-pr-title.ts",
173
+ "test": "vitest",
174
+ "test:watch": "vitest --watch",
175
+ "test:ci": "vitest --coverage"
169
176
  }
170
177
  }