@fabdeh/eslint-config 0.2.0 → 0.2.1

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.d.mts CHANGED
@@ -187,7 +187,7 @@ interface StylisticOptions {
187
187
  */
188
188
  interface TypeScriptParserOptions {
189
189
  /**
190
- * Optional parser options to be used by the TypeScript parser.
190
+ * Additional parser options for TypeScript.
191
191
  */
192
192
  parserOptions?: TSESLint.FlatConfig.ParserOptions;
193
193
  }
@@ -307,7 +307,7 @@ interface CreateConfigOptions {
307
307
  *
308
308
  * @default auto-detected
309
309
  */
310
- typescript?: OverridesOptions & TypeScriptParserOptions;
310
+ typescript?: boolean | (OverridesOptions & TypeScriptParserOptions);
311
311
  /**
312
312
  * Enable stylistic rules.
313
313
  *
@@ -729,5 +729,14 @@ declare function ensurePackages(packages: (string | undefined)[]): Promise<void>
729
729
  * @returns The name of the nearest package.json
730
730
  */
731
731
  declare function findNearestPackageJsonName(directoryPath?: string): Promise<string>;
732
+ type ResolvedOptions<T> = T extends boolean ? never : NonNullable<T>;
733
+ /**
734
+ * Returns the object representation of the configuration or an empty object if it is a boolean.
735
+ *
736
+ * @param options - The {@link CreateConfigOptions} object to extract the sub-options from.
737
+ * @param key - The property name.
738
+ * @returns An object representing the required options.
739
+ */
740
+ declare function resolveSubOptions<K extends keyof CreateConfigOptions>(options: CreateConfigOptions, key: K): ResolvedOptions<CreateConfigOptions[K]>;
732
741
 
733
- export { type AngularOptions, type Awaitable, type CreateConfigOptions, type FilesOptions, type FormattersOptions, GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, type NgrxOperators, type NgrxOptions, type OverridesOptions, STYLISTIC_CONFIG_DEFAULT, type StylisticConfig, type StylisticOptions, type TestingOptions, type TypeScriptParserOptions, type UnicornOptions, angular, comments, createConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
742
+ export { type AngularOptions, type Awaitable, type CreateConfigOptions, type FilesOptions, type FormattersOptions, GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, type NgrxOperators, type NgrxOptions, type OverridesOptions, type ResolvedOptions, STYLISTIC_CONFIG_DEFAULT, type StylisticConfig, type StylisticOptions, type TestingOptions, type TypeScriptParserOptions, type UnicornOptions, angular, comments, createConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
package/dist/index.mjs CHANGED
@@ -10,8 +10,8 @@ import preferArrowFunctions from 'eslint-plugin-prefer-arrow-functions';
10
10
  import unusedImports from 'eslint-plugin-unused-imports';
11
11
  import globals from 'globals';
12
12
  import eslintComments from '@eslint-community/eslint-plugin-eslint-comments';
13
- import * as importX from 'eslint-plugin-import-x';
14
13
  import jsdocPlugin from 'eslint-plugin-jsdoc';
14
+ import * as importX from 'eslint-plugin-import-x';
15
15
  import perfectionistPlugin from 'eslint-plugin-perfectionist';
16
16
  import unicornPlugin from 'eslint-plugin-unicorn';
17
17
  import { mergeProcessors, processorPassThrough } from 'eslint-merge-processors';
@@ -135,6 +135,12 @@ async function findNearestPackageJsonName(directoryPath = resolve()) {
135
135
  return findNearestPackageJsonName(parentDir);
136
136
  }
137
137
  }
138
+ function resolveSubOptions(options, key) {
139
+ if (typeof options[key] === "boolean") {
140
+ return {};
141
+ }
142
+ return options[key] ?? {};
143
+ }
138
144
 
139
145
  async function angular(options = {}) {
140
146
  const angularEslint = await interopDefault(import('angular-eslint'));
@@ -246,7 +252,6 @@ async function angular(options = {}) {
246
252
  function comments() {
247
253
  return tseslint.config({
248
254
  name: "fabdeh/comments/rules",
249
- files: [GLOB_SRC],
250
255
  plugins: {
251
256
  "@eslint-community/eslint-comments": eslintComments
252
257
  },
@@ -272,8 +277,7 @@ function imports(options = {}) {
272
277
  const { stylistic = true } = options;
273
278
  return tseslint.config(
274
279
  {
275
- name: "fabdeh/imports/common/rules",
276
- files: [GLOB_SRC],
280
+ name: "fabdeh/imports/rules",
277
281
  plugins: {
278
282
  "import-x": importX
279
283
  },
@@ -282,7 +286,9 @@ function imports(options = {}) {
282
286
  "import-x/default": "error",
283
287
  "import-x/export": "error",
284
288
  "import-x/first": "error",
289
+ "import-x/named": "error",
285
290
  "import-x/no-absolute-path": "error",
291
+ "import-x/no-deprecated": "error",
286
292
  "import-x/no-duplicates": "error",
287
293
  "import-x/no-empty-named-blocks": "error",
288
294
  "import-x/no-extraneous-dependencies": "error",
@@ -299,15 +305,7 @@ function imports(options = {}) {
299
305
  }
300
306
  },
301
307
  {
302
- name: "fabdeh/imports/js-only/rules",
303
- files: [GLOB_JS],
304
- rules: {
305
- "import-x/named": "error",
306
- "import-x/no-deprecated": "error"
307
- }
308
- },
309
- {
310
- name: "fabdeh/imports/ts-only/rules",
308
+ name: "fabdeh/imports/ts-disables",
311
309
  files: [GLOB_TS],
312
310
  rules: {
313
311
  "import-x/named": "off",
@@ -332,7 +330,6 @@ function javascript(options = {}) {
332
330
  navigator: "readonly",
333
331
  window: "readonly"
334
332
  },
335
- parser: tseslint.parser,
336
333
  parserOptions: {
337
334
  ecmaFeatures: {
338
335
  jsx: true
@@ -348,7 +345,6 @@ function javascript(options = {}) {
348
345
  },
349
346
  {
350
347
  name: "fabdeh/javascript/rules",
351
- files: [GLOB_SRC],
352
348
  plugins: {
353
349
  "@typescript-eslint": tseslint.plugin,
354
350
  "prefer-arrow-functions": preferArrowFunctions,
@@ -475,7 +471,6 @@ function jsdoc(options = {}) {
475
471
  return tseslint.config(
476
472
  {
477
473
  name: "fabdeh/jsdoc/rules",
478
- files: [GLOB_SRC],
479
474
  plugins: { jsdoc: jsdocPlugin },
480
475
  rules: {
481
476
  "jsdoc/check-access": "warn",
@@ -602,6 +597,28 @@ async function markdown(options = {}) {
602
597
  overrides = {}
603
598
  } = options;
604
599
  const markdownPlugin = await interopDefault(import('@eslint/markdown'));
600
+ const parserPlain = {
601
+ meta: {
602
+ name: "parser-plain"
603
+ },
604
+ parseForESLint: (code) => ({
605
+ ast: {
606
+ body: [],
607
+ comments: [],
608
+ loc: { end: code.length, start: 0 },
609
+ range: [0, code.length],
610
+ tokens: [],
611
+ type: "Program"
612
+ },
613
+ // eslint-disable-next-line unicorn/no-null
614
+ scopeManager: null,
615
+ services: { isPlain: true },
616
+ visitorKeys: {
617
+ // eslint-disable-next-line @typescript-eslint/naming-convention
618
+ Program: []
619
+ }
620
+ })
621
+ };
605
622
  return tseslint.config(
606
623
  {
607
624
  name: "fabdeh/markdown/setup",
@@ -616,16 +633,18 @@ async function markdown(options = {}) {
616
633
  processor: mergeProcessors([
617
634
  markdownPlugin.processors.markdown,
618
635
  processorPassThrough
619
- ]),
620
- rules: {
621
- ...markdownPlugin.configs.recommended.at(0)?.rules,
622
- "markdown/no-duplicate-headings": "error"
636
+ ])
637
+ },
638
+ {
639
+ name: "fabdeh/markdown/parser",
640
+ files,
641
+ languageOptions: {
642
+ parser: parserPlain
623
643
  }
624
644
  },
625
645
  {
626
646
  name: "fabdeh/markdown/disables",
627
647
  languageOptions: {
628
- parser: tseslint.parser,
629
648
  parserOptions: {
630
649
  ecmaFeatures: {
631
650
  impliedStrict: true
@@ -659,9 +678,16 @@ async function markdown(options = {}) {
659
678
  "unicode-bom": "off",
660
679
  "unused-imports/no-unused-imports": "off",
661
680
  "unused-imports/no-unused-vars": "off",
662
- "unicorn/filename-case": "off",
663
681
  ...overrides
664
682
  }
683
+ },
684
+ {
685
+ name: "fabdeh/markdown/rules",
686
+ files,
687
+ rules: {
688
+ ...markdownPlugin.configs.recommended.at(0)?.rules,
689
+ "markdown/no-duplicate-headings": "error"
690
+ }
665
691
  }
666
692
  );
667
693
  }
@@ -865,7 +891,6 @@ async function perfectionist() {
865
891
  const tsconfigRootDir = await findNearestPackageJsonName() === "@fabdeh/eslint-config" ? void 0 : getWorkspaceRoot(process.cwd(), process.cwd());
866
892
  return tseslint.config({
867
893
  name: "fabdeh/perfectionist/rules",
868
- files: [GLOB_SRC],
869
894
  plugins: {
870
895
  perfectionist: perfectionistPlugin
871
896
  },
@@ -1143,7 +1168,6 @@ async function stylistic(options = {}) {
1143
1168
  const config = stylisticPlugin.configs.customize({ ...stylisticOptions, flat: true });
1144
1169
  return tseslint.config({
1145
1170
  name: "fabdeh/stylistic/rules",
1146
- files: [GLOB_SRC],
1147
1171
  plugins: {
1148
1172
  "@stylistic": stylisticPlugin
1149
1173
  },
@@ -1249,27 +1273,36 @@ const memberOrdering = {
1249
1273
  };
1250
1274
 
1251
1275
  function typescript(options = {}) {
1252
- const { stylistic = true, parserOptions, overrides } = options;
1276
+ const { stylistic = true, parserOptions = {}, overrides = {} } = options;
1253
1277
  return tseslint.config(
1254
1278
  {
1255
1279
  name: "fabdeh/typescript/setup",
1280
+ files: [GLOB_TS],
1281
+ ignores: [`${GLOB_MARKDOWN}/**`],
1256
1282
  languageOptions: {
1257
- parserOptions: parserOptions ?? {
1258
- projectService: true,
1259
- tsconfigRootDir: getWorkspaceRoot(process.cwd(), process.cwd())
1283
+ parser: tseslint.parser,
1284
+ parserOptions: {
1285
+ sourceType: "module",
1286
+ projectService: {
1287
+ allowDefaultProject: ["*.js"],
1288
+ defaultProject: "tsconfig.json"
1289
+ },
1290
+ tsconfigRootDir: getWorkspaceRoot(process.cwd(), process.cwd()),
1291
+ ...parserOptions
1260
1292
  }
1261
1293
  }
1262
1294
  },
1263
1295
  {
1264
1296
  name: "fabdeh/typescript/rules",
1265
1297
  files: [GLOB_TS],
1298
+ ignores: [`${GLOB_MARKDOWN}/**`],
1266
1299
  plugins: {
1267
1300
  "@typescript-eslint": tseslint.plugin,
1268
1301
  "unused-imports": unusedImports
1269
1302
  },
1270
1303
  rules: {
1271
- ...tseslint.configs.stylisticTypeChecked.find((c) => c.name === "typescript-eslint/eslint-recommended")?.rules,
1272
- ...tseslint.configs.stylisticTypeChecked.find((c) => c.name === "typescript-eslint/strict-type-checked")?.rules,
1304
+ ...tseslint.configs.strictTypeChecked.find((c) => c.name === "typescript-eslint/eslint-recommended")?.rules,
1305
+ ...tseslint.configs.strictTypeChecked.find((c) => c.name === "typescript-eslint/strict-type-checked")?.rules,
1273
1306
  ...stylistic ? tseslint.configs.stylisticTypeChecked.find((c) => c.name === "typescript-eslint/stylistic-type-checked")?.rules : {},
1274
1307
  "@typescript-eslint/array-type": ["error", { default: "array" }],
1275
1308
  "@typescript-eslint/consistent-indexed-object-style": "error",
@@ -1342,7 +1375,6 @@ function unicorn(options = {}) {
1342
1375
  return tseslint.config({
1343
1376
  name: "fabdeh/unicorn/rules",
1344
1377
  plugins: { unicorn: unicornPlugin },
1345
- files: [GLOB_SRC],
1346
1378
  rules: {
1347
1379
  ...options.allRecommended ? unicornPlugin.configs.recommended.rules : {
1348
1380
  "unicorn/catch-error-name": "error",
@@ -1354,7 +1386,7 @@ function unicorn(options = {}) {
1354
1386
  "unicorn/error-message": "error",
1355
1387
  "unicorn/escape-case": "error",
1356
1388
  "unicorn/explicit-length-check": "error",
1357
- "unicorn/filename-case": ["error", { case: "kebabCase" }],
1389
+ "unicorn/filename-case": ["error", { case: "kebabCase", ignore: [/^[A-Z0-9_-]+\.md$/] }],
1358
1390
  "unicorn/new-for-builtins": "error",
1359
1391
  "unicorn/no-abusive-eslint-disable": "error",
1360
1392
  "unicorn/no-anonymous-default-export": "error",
@@ -1563,10 +1595,12 @@ function mergePrettierOptions(options, overrides = {}) {
1563
1595
  return {
1564
1596
  ...options,
1565
1597
  ...overrides,
1598
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
1566
1599
  plugins: [
1567
1600
  ...overrides.plugins ?? [],
1568
1601
  ...options.plugins ?? []
1569
1602
  ]
1603
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment */
1570
1604
  };
1571
1605
  }
1572
1606
  async function formatters(options = {}, stylistic = {}) {
@@ -1788,6 +1822,7 @@ async function createConfig(options = {}, ...userConfigs) {
1788
1822
  gitignore: enableGitignore = true,
1789
1823
  ngrx: enableNgrx = NGRX_PACKAGES.some((p) => isPackageExists(p)),
1790
1824
  tailwindcss: enableTailwind = isPackageExists("tailwindcss"),
1825
+ typescript: enableTypescript = isPackageExists("typescript"),
1791
1826
  unicorn: enableUnicorn = true,
1792
1827
  vitest: enableVitest = isPackageExists("vitest")
1793
1828
  } = options;
@@ -1811,38 +1846,47 @@ async function createConfig(options = {}, ...userConfigs) {
1811
1846
  configs.push(
1812
1847
  ignores(options.ignores),
1813
1848
  javascript({ overrides: options.javascript?.overrides }),
1814
- typescript({
1815
- stylistic: stylisticOptions,
1816
- parserOptions: options.typescript?.parserOptions,
1817
- overrides: options.typescript?.overrides
1818
- }),
1819
1849
  comments(),
1820
- imports({ stylistic: stylisticOptions }),
1850
+ // TODO: add node rules ???
1821
1851
  jsdoc({ stylistic: stylisticOptions }),
1852
+ imports({ stylistic: stylisticOptions }),
1822
1853
  perfectionist()
1823
1854
  );
1824
1855
  if (enableUnicorn) {
1825
- configs.push(unicorn(typeof enableUnicorn === "object" ? enableUnicorn : {}));
1856
+ const unicornOptions = resolveSubOptions(options, "unicorn");
1857
+ configs.push(unicorn(unicornOptions));
1858
+ }
1859
+ if (enableTypescript) {
1860
+ const typescriptOptions = resolveSubOptions(options, "typescript");
1861
+ configs.push(typescript({
1862
+ ...typescriptOptions,
1863
+ stylistic: stylisticOptions
1864
+ }));
1826
1865
  }
1827
1866
  if (stylisticOptions) {
1828
1867
  configs.push(stylistic({ stylistic: stylisticOptions }));
1829
1868
  }
1830
1869
  if (enableAngular) {
1831
- configs.push(angular(typeof enableAngular === "object" ? enableAngular : {}));
1870
+ const angularOptions = resolveSubOptions(options, "angular");
1871
+ configs.push(angular(angularOptions));
1832
1872
  }
1833
1873
  if (enableNgrx) {
1834
- configs.push(ngrx(typeof enableNgrx === "object" ? enableNgrx : {}));
1874
+ const ngrxOptions = resolveSubOptions(options, "ngrx");
1875
+ configs.push(ngrx(ngrxOptions));
1835
1876
  }
1836
1877
  if (enableVitest) {
1837
- configs.push(vitest(typeof enableVitest === "object" ? enableVitest : {}));
1878
+ const vitestOptions = resolveSubOptions(options, "vitest");
1879
+ configs.push(vitest(vitestOptions));
1838
1880
  }
1839
1881
  if (enableTailwind) {
1840
- configs.push(tailwindcss(typeof enableTailwind === "object" ? enableTailwind : {}));
1882
+ const tailwindcssOptions = resolveSubOptions(options, "tailwindcss");
1883
+ configs.push(tailwindcss(tailwindcssOptions));
1841
1884
  }
1842
1885
  if (options.jsonc ?? true) {
1886
+ const jsoncOptions = resolveSubOptions(options, "jsonc");
1843
1887
  configs.push(
1844
1888
  jsonc({
1845
- overrides: typeof options.jsonc === "object" ? options.jsonc.overrides : {},
1889
+ ...jsoncOptions,
1846
1890
  stylistic: stylisticOptions
1847
1891
  }),
1848
1892
  sortPackageJson(),
@@ -1850,21 +1894,22 @@ async function createConfig(options = {}, ...userConfigs) {
1850
1894
  );
1851
1895
  }
1852
1896
  if (options.yaml ?? true) {
1897
+ const yamlOptions = resolveSubOptions(options, "yaml");
1853
1898
  configs.push(yaml({
1854
- overrides: typeof options.yaml === "object" ? options.yaml.overrides : {},
1899
+ ...yamlOptions,
1855
1900
  stylistic: stylisticOptions
1856
1901
  }));
1857
1902
  }
1858
1903
  if (options.toml ?? true) {
1904
+ const tomlOptions = resolveSubOptions(options, "toml");
1859
1905
  configs.push(toml({
1860
- overrides: typeof options.toml === "object" ? options.toml.overrides : {},
1906
+ ...tomlOptions,
1861
1907
  stylistic: stylisticOptions
1862
1908
  }));
1863
1909
  }
1864
1910
  if (options.markdown ?? true) {
1865
- configs.push(markdown({
1866
- overrides: typeof options.markdown === "object" ? options.markdown.overrides : {}
1867
- }));
1911
+ const markdownOptions = resolveSubOptions(options, "markdown");
1912
+ configs.push(markdown(markdownOptions));
1868
1913
  }
1869
1914
  if (options.formatters) {
1870
1915
  configs.push(formatters(options.formatters, typeof stylisticOptions === "boolean" ? {} : stylisticOptions));
@@ -1881,4 +1926,4 @@ async function createConfig(options = {}, ...userConfigs) {
1881
1926
  return tseslint.config(...await Promise.all(configs), ...await Promise.all(userConfigs));
1882
1927
  }
1883
1928
 
1884
- export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, createConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
1929
+ export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, createConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, 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.2.0",
4
+ "version": "0.2.1",
5
5
  "packageManager": "pnpm@10.4.1",
6
6
  "description": "My personal eslint config preset",
7
7
  "author": {