@favorodera/eslint-config 0.0.0 → 0.0.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.cjs +212 -444
- package/dist/index.d.cts +4417 -1649
- package/dist/index.d.mts +4418 -1650
- package/dist/index.mjs +211 -443
- package/package.json +3 -4
package/dist/index.mjs
CHANGED
|
@@ -1,50 +1,13 @@
|
|
|
1
|
-
import { FlatConfigComposer } from "eslint-flat-config-utils";
|
|
1
|
+
import { FlatConfigComposer, renamePluginsInRules } from "eslint-flat-config-utils";
|
|
2
2
|
import { defu } from "defu";
|
|
3
3
|
import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
|
|
4
|
+
import vueBlocksProcessor from "eslint-processor-vue-blocks";
|
|
4
5
|
import globals from "globals";
|
|
5
|
-
//#region src/utils.ts
|
|
6
|
-
/**
|
|
7
|
-
* Return the default export from a module-like object.
|
|
8
|
-
* If the module has no default export, return the original resolved value.
|
|
9
|
-
*
|
|
10
|
-
* @param module - module or promise resolving to a module
|
|
11
|
-
* @returns resolved module default or original module
|
|
12
|
-
*/
|
|
13
|
-
async function getModuleDefault(module) {
|
|
14
|
-
const resolvedModule = await module;
|
|
15
|
-
return resolvedModule.default || resolvedModule;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Normalize boolean or options value into merged options or null.
|
|
19
|
-
* Returns null when the input is false or undefined.
|
|
20
|
-
*
|
|
21
|
-
* @param value - boolean, options object, or undefined
|
|
22
|
-
* @param defaults - defaults to merge with
|
|
23
|
-
* @returns merged options or false
|
|
24
|
-
*/
|
|
25
|
-
function resolveOptions(value, defaults) {
|
|
26
|
-
if (!value) return false;
|
|
27
|
-
return defu(value === true ? {} : value, defaults);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Rename rules by replacing configured plugin prefixes.
|
|
31
|
-
*
|
|
32
|
-
* @param rules - rules object to rename
|
|
33
|
-
* @param map - prefix map used for renaming
|
|
34
|
-
* @returns renamed rules object
|
|
35
|
-
*/
|
|
36
|
-
function renameRules(rules, map) {
|
|
37
|
-
return Object.fromEntries(Object.entries(rules).map(([key, value]) => {
|
|
38
|
-
for (const [from, to] of Object.entries(map)) if (key.startsWith(`${from}/`)) return [to + key.slice(from.length), value];
|
|
39
|
-
return [key, value];
|
|
40
|
-
}));
|
|
41
|
-
}
|
|
42
|
-
//#endregion
|
|
43
6
|
//#region src/globs.ts
|
|
44
7
|
/** Glob pattern for JavaScript linting */
|
|
45
|
-
const jsGlob = "
|
|
8
|
+
const jsGlob = "**/*.{js,cjs,mjs}";
|
|
46
9
|
/** Glob pattern for TypeScript linting */
|
|
47
|
-
const tsGlob = "
|
|
10
|
+
const tsGlob = "**/*.{ts,cts,mts}";
|
|
48
11
|
/** Glob pattern for Vue linting */
|
|
49
12
|
const vueGlob = "**/*.vue";
|
|
50
13
|
/** Glob pattern for Markdown linting */
|
|
@@ -54,8 +17,8 @@ const mdGlob = "**/*.md";
|
|
|
54
17
|
* Includes common build outputs, dependencies, caches, and temporary files
|
|
55
18
|
*/
|
|
56
19
|
const ignoresGlob = [
|
|
57
|
-
"**/node_modules",
|
|
58
|
-
"**/dist",
|
|
20
|
+
"**/node_modules/**",
|
|
21
|
+
"**/dist/**",
|
|
59
22
|
"**/package-lock.json",
|
|
60
23
|
"**/yarn.lock",
|
|
61
24
|
"**/pnpm-lock.yaml",
|
|
@@ -91,6 +54,35 @@ const ignoresGlob = [
|
|
|
91
54
|
"**/.*/skills"
|
|
92
55
|
];
|
|
93
56
|
//#endregion
|
|
57
|
+
//#region src/utils.ts
|
|
58
|
+
/**
|
|
59
|
+
* Resolves a module (or a promise of one) and returns its default export
|
|
60
|
+
* if present, otherwise returns the module itself.
|
|
61
|
+
*
|
|
62
|
+
* Handles both ESM modules (which wrap exports under `.default`) and
|
|
63
|
+
* CJS / plain-object modules uniformly.
|
|
64
|
+
*
|
|
65
|
+
* @param module - A module or a promise that resolves to one
|
|
66
|
+
* @returns The `.default` export if it exists, otherwise the module itself
|
|
67
|
+
*/
|
|
68
|
+
async function importModule(module) {
|
|
69
|
+
const resolved = await module;
|
|
70
|
+
if (resolved !== null && typeof resolved === "object" && "default" in resolved) return resolved.default;
|
|
71
|
+
return resolved;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Normalize boolean or options value into merged options or null.
|
|
75
|
+
* Returns null when the input is false or undefined.
|
|
76
|
+
*
|
|
77
|
+
* @param value - boolean, options object, or undefined
|
|
78
|
+
* @param defaults - defaults to merge with
|
|
79
|
+
* @returns merged options or false
|
|
80
|
+
*/
|
|
81
|
+
function resolveOptions(value, defaults) {
|
|
82
|
+
if (!value) return false;
|
|
83
|
+
return defu(value === true ? {} : value, defaults);
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
94
86
|
//#region src/configs/vue.ts
|
|
95
87
|
const sfcBlocksDefaults = { blocks: {
|
|
96
88
|
styles: true,
|
|
@@ -101,22 +93,21 @@ const vueDefaults = {
|
|
|
101
93
|
files: [vueGlob],
|
|
102
94
|
sfcBlocks: sfcBlocksDefaults
|
|
103
95
|
};
|
|
104
|
-
/**
|
|
105
|
-
* Vue SFC linting via `vue-eslint-parser`, `eslint-plugin-vue`, `typescript-eslint(parser)`.
|
|
106
|
-
* @param options - Vue configuration options
|
|
107
|
-
* @returns Promise resolving to Vue ESLint config items
|
|
108
|
-
*/
|
|
109
96
|
async function vue(options) {
|
|
110
97
|
const resolved = defu(options, vueDefaults);
|
|
111
98
|
const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
|
|
112
|
-
const [vuePlugin, vueParser, tsEsLint
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
getModuleDefault(import("eslint-processor-vue-blocks"))
|
|
99
|
+
const [vuePlugin, vueParser, tsEsLint] = await Promise.all([
|
|
100
|
+
importModule(import("eslint-plugin-vue")),
|
|
101
|
+
importModule(import("vue-eslint-parser")),
|
|
102
|
+
importModule(import("typescript-eslint"))
|
|
117
103
|
]);
|
|
104
|
+
const inheritedRules = Object.assign({}, ...[
|
|
105
|
+
...vuePlugin.configs["flat/essential"],
|
|
106
|
+
...vuePlugin.configs["flat/strongly-recommended"],
|
|
107
|
+
...vuePlugin.configs["flat/recommended"]
|
|
108
|
+
].map((config) => config?.rules || {}));
|
|
118
109
|
return [{
|
|
119
|
-
name: "favorodera/vue
|
|
110
|
+
name: "favorodera/vue",
|
|
120
111
|
plugins: { vue: vuePlugin },
|
|
121
112
|
files: resolved.files,
|
|
122
113
|
languageOptions: {
|
|
@@ -145,19 +136,7 @@ async function vue(options) {
|
|
|
145
136
|
},
|
|
146
137
|
processor: sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]),
|
|
147
138
|
rules: {
|
|
148
|
-
...
|
|
149
|
-
...vuePlugin.configs["flat/essential"].map((config) => config.rules).reduce((accumulator, currentConfig) => ({
|
|
150
|
-
...accumulator,
|
|
151
|
-
...currentConfig
|
|
152
|
-
}), {}),
|
|
153
|
-
...vuePlugin.configs["flat/strongly-recommended"].map((config) => config.rules).reduce((accumulator, currentConfig) => ({
|
|
154
|
-
...accumulator,
|
|
155
|
-
...currentConfig
|
|
156
|
-
}), {}),
|
|
157
|
-
...vuePlugin.configs["flat/recommended"].map((config) => config.rules).reduce((accumulator, currentConfig) => ({
|
|
158
|
-
...accumulator,
|
|
159
|
-
...currentConfig
|
|
160
|
-
}), {}),
|
|
139
|
+
...inheritedRules,
|
|
161
140
|
"vue/block-order": ["error", { order: [
|
|
162
141
|
"script",
|
|
163
142
|
"template",
|
|
@@ -179,43 +158,6 @@ async function vue(options) {
|
|
|
179
158
|
}];
|
|
180
159
|
}
|
|
181
160
|
//#endregion
|
|
182
|
-
//#region src/configs/typescript.ts
|
|
183
|
-
const typescriptDefaults = { files: [tsGlob] };
|
|
184
|
-
/**
|
|
185
|
-
* Extract and merge rules from a compatible config array.
|
|
186
|
-
* @param configs - Array of compatible ESLint configs
|
|
187
|
-
* @returns Merged rules object from all configs
|
|
188
|
-
*/
|
|
189
|
-
function extractRules(configs) {
|
|
190
|
-
return Object.assign({}, ...configs.map((config) => config.rules || {}));
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Typescript linting via `typescript-eslint`.
|
|
194
|
-
* @param options - TypeScript configuration options
|
|
195
|
-
* @returns Promise resolving to TypeScript ESLint config items
|
|
196
|
-
*/
|
|
197
|
-
async function typescript(options) {
|
|
198
|
-
const resolved = defu(options, typescriptDefaults);
|
|
199
|
-
const tsEsLint = await getModuleDefault(import("typescript-eslint"));
|
|
200
|
-
return [{
|
|
201
|
-
name: "favorodera/typescript/rules",
|
|
202
|
-
files: resolved.files,
|
|
203
|
-
plugins: { ts: tsEsLint.plugin },
|
|
204
|
-
languageOptions: {
|
|
205
|
-
parser: tsEsLint.parser,
|
|
206
|
-
parserOptions: { sourceType: "module" }
|
|
207
|
-
},
|
|
208
|
-
rules: {
|
|
209
|
-
...renameRules(extractRules(tsEsLint.configs.strict), { "@typescript-eslint": "ts" }),
|
|
210
|
-
...renameRules(extractRules(tsEsLint.configs.stylistic), { "@typescript-eslint": "ts" }),
|
|
211
|
-
"ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
|
|
212
|
-
"ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
|
|
213
|
-
"ts/array-type": ["error", { default: "array" }],
|
|
214
|
-
...resolved.overrides
|
|
215
|
-
}
|
|
216
|
-
}];
|
|
217
|
-
}
|
|
218
|
-
//#endregion
|
|
219
161
|
//#region src/configs/ignores.ts
|
|
220
162
|
const defaultPatterns = ignoresGlob;
|
|
221
163
|
/**
|
|
@@ -230,141 +172,25 @@ function ignores(patterns = []) {
|
|
|
230
172
|
}];
|
|
231
173
|
}
|
|
232
174
|
//#endregion
|
|
233
|
-
//#region src/configs/stylistic.ts
|
|
234
|
-
const stylisticDefaults = {
|
|
235
|
-
indent: 2,
|
|
236
|
-
experimental: false,
|
|
237
|
-
quotes: "single",
|
|
238
|
-
semi: false,
|
|
239
|
-
jsx: false
|
|
240
|
-
};
|
|
241
|
-
/**
|
|
242
|
-
* Code style via `@stylistic/eslint-plugin`.
|
|
243
|
-
* @param options - Stylistic configuration options
|
|
244
|
-
* @returns Promise resolving to stylistic ESLint config items
|
|
245
|
-
*/
|
|
246
|
-
async function stylistic(options) {
|
|
247
|
-
const resolved = defu(options, stylisticDefaults);
|
|
248
|
-
const stylePlugin = await getModuleDefault(import("@stylistic/eslint-plugin"));
|
|
249
|
-
const customizedStyleConfig = stylePlugin.configs.customize({
|
|
250
|
-
pluginName: "style",
|
|
251
|
-
...resolved
|
|
252
|
-
});
|
|
253
|
-
return [{
|
|
254
|
-
name: "favorodera/stylistic/rules",
|
|
255
|
-
plugins: { style: stylePlugin },
|
|
256
|
-
rules: {
|
|
257
|
-
...customizedStyleConfig.rules,
|
|
258
|
-
"style/quotes": [
|
|
259
|
-
"error",
|
|
260
|
-
"single",
|
|
261
|
-
{ avoidEscape: true }
|
|
262
|
-
],
|
|
263
|
-
"style/no-multiple-empty-lines": ["error", {
|
|
264
|
-
max: 2,
|
|
265
|
-
maxEOF: 2,
|
|
266
|
-
maxBOF: 0
|
|
267
|
-
}],
|
|
268
|
-
"style/padded-blocks": "off",
|
|
269
|
-
"style/no-trailing-spaces": ["error", { skipBlankLines: true }],
|
|
270
|
-
"style/brace-style": "off",
|
|
271
|
-
"style/generator-star-spacing": ["error", {
|
|
272
|
-
after: true,
|
|
273
|
-
before: false
|
|
274
|
-
}],
|
|
275
|
-
"style/yield-star-spacing": ["error", {
|
|
276
|
-
after: true,
|
|
277
|
-
before: false
|
|
278
|
-
}],
|
|
279
|
-
...resolved.overrides
|
|
280
|
-
}
|
|
281
|
-
}];
|
|
282
|
-
}
|
|
283
|
-
//#endregion
|
|
284
|
-
//#region src/configs/tailwind.ts
|
|
285
|
-
const tailwindDefaults = {
|
|
286
|
-
files: [
|
|
287
|
-
jsGlob,
|
|
288
|
-
tsGlob,
|
|
289
|
-
vueGlob
|
|
290
|
-
],
|
|
291
|
-
settings: { detectComponentClasses: true }
|
|
292
|
-
};
|
|
293
|
-
/**
|
|
294
|
-
* Tailwind linting via `eslint-plugin-better-tailwindcss`.
|
|
295
|
-
* @param options - Tailwind configuration options
|
|
296
|
-
* @returns Promise resolving to Tailwind ESLint config items
|
|
297
|
-
*/
|
|
298
|
-
async function tailwind(options) {
|
|
299
|
-
const resolved = defu(options, tailwindDefaults);
|
|
300
|
-
const tailwindPlugin = await getModuleDefault(import("eslint-plugin-better-tailwindcss"));
|
|
301
|
-
return [{
|
|
302
|
-
name: "favorodera/tailwind/rules",
|
|
303
|
-
plugins: { tailwind: tailwindPlugin },
|
|
304
|
-
files: resolved.files,
|
|
305
|
-
settings: { tailwindcss: resolved.settings },
|
|
306
|
-
rules: {
|
|
307
|
-
...renameRules(tailwindPlugin.configs["recommended-error"].rules, { "better-tailwindcss": "tailwind" }),
|
|
308
|
-
...renameRules(tailwindPlugin.configs["stylistic-error"].rules, { "better-tailwindcss": "tailwind" }),
|
|
309
|
-
"tailwind/no-unregistered-classes": "off",
|
|
310
|
-
"tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
|
|
311
|
-
...resolved.overrides
|
|
312
|
-
}
|
|
313
|
-
}];
|
|
314
|
-
}
|
|
315
|
-
//#endregion
|
|
316
|
-
//#region src/configs/comments.ts
|
|
317
|
-
const commentsDefaults = { files: [
|
|
318
|
-
jsGlob,
|
|
319
|
-
tsGlob,
|
|
320
|
-
vueGlob
|
|
321
|
-
] };
|
|
322
|
-
/**
|
|
323
|
-
* Comments linting via `@eslint-community/eslint-plugin-eslint-comments`
|
|
324
|
-
* @param options - Comments configuration options
|
|
325
|
-
* @returns Promise resolving to comments ESLint config items
|
|
326
|
-
*/
|
|
327
|
-
async function comments(options) {
|
|
328
|
-
const resolved = defu(options, commentsDefaults);
|
|
329
|
-
const commentsPlugin = await getModuleDefault(import("@eslint-community/eslint-plugin-eslint-comments"));
|
|
330
|
-
return [{
|
|
331
|
-
name: "favorodera/comments/rules",
|
|
332
|
-
files: resolved.files,
|
|
333
|
-
plugins: { comments: commentsPlugin },
|
|
334
|
-
rules: {
|
|
335
|
-
...renameRules(commentsPlugin.configs.recommended?.rules || {}, { "@eslint-community/eslint-comments": "comments" }),
|
|
336
|
-
"comments/no-aggregating-enable": "error",
|
|
337
|
-
"comments/no-duplicate-disable": "error",
|
|
338
|
-
"comments/no-unlimited-disable": "error",
|
|
339
|
-
"comments/no-unused-enable": "error",
|
|
340
|
-
...resolved.overrides
|
|
341
|
-
}
|
|
342
|
-
}];
|
|
343
|
-
}
|
|
344
|
-
//#endregion
|
|
345
175
|
//#region src/configs/imports.ts
|
|
346
176
|
const importsDefaults = { files: [
|
|
347
177
|
jsGlob,
|
|
348
178
|
tsGlob,
|
|
349
179
|
vueGlob
|
|
350
180
|
] };
|
|
351
|
-
/**
|
|
352
|
-
* Imports & unused imports linting via `eslint-plugin-import-lite` and `eslint-plugin-unused-imports`.
|
|
353
|
-
* @param options - Imports & unused imports configuration options
|
|
354
|
-
* @returns Promise resolving to imports & unused imports ESLint config items
|
|
355
|
-
*/
|
|
356
181
|
async function imports(options) {
|
|
357
182
|
const resolved = defu(options, importsDefaults);
|
|
358
|
-
const [importPlugin, unusedImportsPlugin] = await Promise.all([
|
|
183
|
+
const [importPlugin, unusedImportsPlugin] = await Promise.all([importModule(import("eslint-plugin-import-lite")), importModule(import("eslint-plugin-unused-imports"))]);
|
|
184
|
+
const inheritedRules = importPlugin.configs.recommended?.rules || {};
|
|
359
185
|
return [{
|
|
360
|
-
name: "favorodera/imports
|
|
186
|
+
name: "favorodera/imports",
|
|
361
187
|
files: resolved.files,
|
|
362
188
|
plugins: {
|
|
363
189
|
"import": importPlugin,
|
|
364
190
|
"unused-imports": unusedImportsPlugin
|
|
365
191
|
},
|
|
366
192
|
rules: {
|
|
367
|
-
...
|
|
193
|
+
...renamePluginsInRules(inheritedRules, { "import-lite": "import" }),
|
|
368
194
|
"import/consistent-type-specifier-style": ["error", "top-level"],
|
|
369
195
|
"import/first": "error",
|
|
370
196
|
"import/no-duplicates": "error",
|
|
@@ -384,34 +210,6 @@ async function imports(options) {
|
|
|
384
210
|
}];
|
|
385
211
|
}
|
|
386
212
|
//#endregion
|
|
387
|
-
//#region src/configs/markdown.ts
|
|
388
|
-
const markdownDefaults = {
|
|
389
|
-
files: [mdGlob],
|
|
390
|
-
gfm: true
|
|
391
|
-
};
|
|
392
|
-
/**
|
|
393
|
-
* Markdown linting via `@eslint/markdown`.
|
|
394
|
-
* @param options - Markdown configuration options
|
|
395
|
-
* @returns Promise resolving to Markdown ESLint config items
|
|
396
|
-
*/
|
|
397
|
-
async function markdown(options) {
|
|
398
|
-
const resolved = defu(options, markdownDefaults);
|
|
399
|
-
const markdownPlugin = await getModuleDefault(import("@eslint/markdown"));
|
|
400
|
-
return [{
|
|
401
|
-
name: "favorodera/markdown/rules",
|
|
402
|
-
files: resolved.files,
|
|
403
|
-
plugins: { md: markdownPlugin },
|
|
404
|
-
processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
|
|
405
|
-
language: resolved.gfm ? "md/gfm" : "md/commonmark",
|
|
406
|
-
rules: {
|
|
407
|
-
...renameRules(markdownPlugin.configs.recommended[0]?.rules || {}, { markdown: "md" }),
|
|
408
|
-
"md/fenced-code-language": "off",
|
|
409
|
-
"md/no-missing-label-refs": "off",
|
|
410
|
-
...resolved.overrides
|
|
411
|
-
}
|
|
412
|
-
}];
|
|
413
|
-
}
|
|
414
|
-
//#endregion
|
|
415
213
|
//#region src/configs/javascript.ts
|
|
416
214
|
const javascriptDefaults = { files: [
|
|
417
215
|
jsGlob,
|
|
@@ -425,9 +223,9 @@ const javascriptDefaults = { files: [
|
|
|
425
223
|
*/
|
|
426
224
|
async function javascript(options) {
|
|
427
225
|
const resolved = defu(options, javascriptDefaults);
|
|
428
|
-
const
|
|
226
|
+
const inheritedRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
|
|
429
227
|
return [{
|
|
430
|
-
name: "favorodera/javascript
|
|
228
|
+
name: "favorodera/javascript",
|
|
431
229
|
files: resolved.files,
|
|
432
230
|
languageOptions: {
|
|
433
231
|
ecmaVersion: "latest",
|
|
@@ -442,189 +240,156 @@ async function javascript(options) {
|
|
|
442
240
|
}
|
|
443
241
|
},
|
|
444
242
|
linterOptions: { reportUnusedDisableDirectives: true },
|
|
445
|
-
plugins: { js: jsPlugin },
|
|
446
243
|
rules: {
|
|
447
|
-
...
|
|
244
|
+
...inheritedRules,
|
|
448
245
|
"accessor-pairs": ["error", {
|
|
449
246
|
enforceForClassMembers: true,
|
|
450
247
|
setWithoutGet: true
|
|
451
248
|
}],
|
|
452
249
|
"array-callback-return": "error",
|
|
453
250
|
"block-scoped-var": "error",
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
"
|
|
477
|
-
"no-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
"
|
|
512
|
-
"no-prototype-builtins": "error",
|
|
513
|
-
"no-redeclare": ["error", { builtinGlobals: false }],
|
|
514
|
-
"no-regex-spaces": "error",
|
|
515
|
-
"no-restricted-globals": [
|
|
516
|
-
"error",
|
|
517
|
-
{
|
|
518
|
-
message: "Use `globalThis` instead.",
|
|
519
|
-
name: "global"
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
message: "Use `globalThis` instead.",
|
|
523
|
-
name: "self"
|
|
524
|
-
}
|
|
525
|
-
],
|
|
526
|
-
"no-restricted-properties": [
|
|
527
|
-
"error",
|
|
528
|
-
{
|
|
529
|
-
message: "Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.",
|
|
530
|
-
property: "__proto__"
|
|
531
|
-
},
|
|
532
|
-
{
|
|
533
|
-
message: "Use `Object.defineProperty` instead.",
|
|
534
|
-
property: "__defineGetter__"
|
|
535
|
-
},
|
|
536
|
-
{
|
|
537
|
-
message: "Use `Object.defineProperty` instead.",
|
|
538
|
-
property: "__defineSetter__"
|
|
539
|
-
},
|
|
540
|
-
{
|
|
541
|
-
message: "Use `Object.getOwnPropertyDescriptor` instead.",
|
|
542
|
-
property: "__lookupGetter__"
|
|
543
|
-
},
|
|
544
|
-
{
|
|
545
|
-
message: "Use `Object.getOwnPropertyDescriptor` instead.",
|
|
546
|
-
property: "__lookupSetter__"
|
|
547
|
-
}
|
|
548
|
-
],
|
|
549
|
-
"no-restricted-syntax": [
|
|
550
|
-
"error",
|
|
551
|
-
"TSEnumDeclaration[const=true]",
|
|
552
|
-
"TSExportAssignment"
|
|
553
|
-
],
|
|
554
|
-
"no-self-assign": ["error", { props: true }],
|
|
555
|
-
"no-self-compare": "error",
|
|
556
|
-
"no-sequences": "error",
|
|
557
|
-
"no-shadow-restricted-names": "error",
|
|
558
|
-
"no-sparse-arrays": "error",
|
|
559
|
-
"no-template-curly-in-string": "error",
|
|
560
|
-
"no-this-before-super": "error",
|
|
561
|
-
"no-throw-literal": "error",
|
|
562
|
-
"no-undef": "error",
|
|
563
|
-
"no-undef-init": "error",
|
|
564
|
-
"no-unexpected-multiline": "error",
|
|
565
|
-
"no-unmodified-loop-condition": "error",
|
|
566
|
-
"no-unneeded-ternary": ["error", { defaultAssignment: false }],
|
|
567
|
-
"no-unreachable": "error",
|
|
568
|
-
"no-unreachable-loop": "error",
|
|
569
|
-
"no-unsafe-finally": "error",
|
|
570
|
-
"no-unsafe-negation": "error",
|
|
571
|
-
"no-unused-expressions": ["error", {
|
|
572
|
-
allowShortCircuit: true,
|
|
573
|
-
allowTaggedTemplates: true,
|
|
574
|
-
allowTernary: true
|
|
575
|
-
}],
|
|
576
|
-
"no-unused-vars": ["error", {
|
|
577
|
-
args: "none",
|
|
578
|
-
caughtErrors: "none",
|
|
579
|
-
ignoreRestSiblings: true,
|
|
580
|
-
vars: "all"
|
|
581
|
-
}],
|
|
582
|
-
"no-use-before-define": ["error", {
|
|
583
|
-
classes: false,
|
|
584
|
-
functions: false,
|
|
585
|
-
variables: true
|
|
586
|
-
}],
|
|
587
|
-
"no-useless-backreference": "error",
|
|
588
|
-
"no-useless-call": "error",
|
|
589
|
-
"no-useless-catch": "error",
|
|
590
|
-
"no-useless-computed-key": "error",
|
|
591
|
-
"no-useless-constructor": "error",
|
|
592
|
-
"no-useless-rename": "error",
|
|
593
|
-
"no-useless-return": "error",
|
|
594
|
-
"no-var": "error",
|
|
595
|
-
"no-with": "error",
|
|
596
|
-
"object-shorthand": [
|
|
251
|
+
...resolved.overrides
|
|
252
|
+
}
|
|
253
|
+
}];
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region src/configs/markdown.ts
|
|
257
|
+
const markdownDefaults = {
|
|
258
|
+
files: [mdGlob],
|
|
259
|
+
gfm: true
|
|
260
|
+
};
|
|
261
|
+
async function markdown(options) {
|
|
262
|
+
const resolved = defu(options, markdownDefaults);
|
|
263
|
+
const markdownPlugin = await importModule(import("@eslint/markdown"));
|
|
264
|
+
const inheritedRules = Object.assign({}, ...[...markdownPlugin.configs.recommended].map((config) => config?.rules || {}));
|
|
265
|
+
return [{
|
|
266
|
+
name: "favorodera/markdown",
|
|
267
|
+
files: resolved.files,
|
|
268
|
+
plugins: { md: markdownPlugin },
|
|
269
|
+
processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
|
|
270
|
+
language: resolved.gfm ? "md/gfm" : "md/commonmark",
|
|
271
|
+
rules: {
|
|
272
|
+
...renamePluginsInRules(inheritedRules, { markdown: "md" }),
|
|
273
|
+
"md/fenced-code-language": "off",
|
|
274
|
+
"md/no-missing-label-refs": "off",
|
|
275
|
+
...resolved.overrides
|
|
276
|
+
}
|
|
277
|
+
}];
|
|
278
|
+
}
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/configs/stylistic.ts
|
|
281
|
+
const stylisticDefaults = {
|
|
282
|
+
settings: {
|
|
283
|
+
indent: 2,
|
|
284
|
+
experimental: false,
|
|
285
|
+
quotes: "single",
|
|
286
|
+
semi: false,
|
|
287
|
+
jsx: false
|
|
288
|
+
},
|
|
289
|
+
files: [
|
|
290
|
+
jsGlob,
|
|
291
|
+
tsGlob,
|
|
292
|
+
vueGlob
|
|
293
|
+
]
|
|
294
|
+
};
|
|
295
|
+
async function stylistic(options) {
|
|
296
|
+
const resolved = defu(options, stylisticDefaults);
|
|
297
|
+
const config = (await importModule(import("@stylistic/eslint-plugin"))).configs.customize({
|
|
298
|
+
pluginName: "style",
|
|
299
|
+
...resolved.settings
|
|
300
|
+
});
|
|
301
|
+
const inheritedRules = config?.rules || {};
|
|
302
|
+
return [{
|
|
303
|
+
...config,
|
|
304
|
+
name: "favorodera/stylistic",
|
|
305
|
+
files: resolved.files,
|
|
306
|
+
rules: {
|
|
307
|
+
...inheritedRules,
|
|
308
|
+
"style/quotes": [
|
|
597
309
|
"error",
|
|
598
|
-
"
|
|
599
|
-
{
|
|
600
|
-
avoidQuotes: true,
|
|
601
|
-
ignoreConstructors: false
|
|
602
|
-
}
|
|
310
|
+
"single",
|
|
311
|
+
{ avoidEscape: true }
|
|
603
312
|
],
|
|
604
|
-
"
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
313
|
+
"style/no-multiple-empty-lines": ["error", {
|
|
314
|
+
max: 2,
|
|
315
|
+
maxEOF: 2,
|
|
316
|
+
maxBOF: 0
|
|
608
317
|
}],
|
|
609
|
-
"
|
|
610
|
-
|
|
611
|
-
|
|
318
|
+
"style/padded-blocks": "off",
|
|
319
|
+
"style/no-trailing-spaces": ["error", { skipBlankLines: true }],
|
|
320
|
+
"style/brace-style": "off",
|
|
321
|
+
"style/generator-star-spacing": ["error", {
|
|
322
|
+
after: true,
|
|
323
|
+
before: false
|
|
612
324
|
}],
|
|
613
|
-
"
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
"prefer-rest-params": "error",
|
|
617
|
-
"prefer-spread": "error",
|
|
618
|
-
"prefer-template": "error",
|
|
619
|
-
"symbol-description": "error",
|
|
620
|
-
"unicode-bom": ["error", "never"],
|
|
621
|
-
"use-isnan": ["error", {
|
|
622
|
-
enforceForIndexOf: true,
|
|
623
|
-
enforceForSwitchCase: true
|
|
325
|
+
"style/yield-star-spacing": ["error", {
|
|
326
|
+
after: true,
|
|
327
|
+
before: false
|
|
624
328
|
}],
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
329
|
+
...resolved.overrides
|
|
330
|
+
}
|
|
331
|
+
}];
|
|
332
|
+
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/configs/tailwind.ts
|
|
335
|
+
const tailwindDefaults = {
|
|
336
|
+
files: [
|
|
337
|
+
jsGlob,
|
|
338
|
+
tsGlob,
|
|
339
|
+
vueGlob
|
|
340
|
+
],
|
|
341
|
+
settings: { detectComponentClasses: true }
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* Tailwind linting via `eslint-plugin-better-tailwindcss`.
|
|
345
|
+
* @param options - Tailwind configuration options
|
|
346
|
+
* @returns Promise resolving to Tailwind ESLint config items
|
|
347
|
+
*/
|
|
348
|
+
async function tailwind(options) {
|
|
349
|
+
const resolved = defu(options, tailwindDefaults);
|
|
350
|
+
const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
|
|
351
|
+
const inheritedRules = {
|
|
352
|
+
...tailwindPlugin.configs["recommended-error"].rules,
|
|
353
|
+
...tailwindPlugin.configs["stylistic-error"].rules
|
|
354
|
+
};
|
|
355
|
+
return [{
|
|
356
|
+
name: "favorodera/tailwind",
|
|
357
|
+
files: resolved.files,
|
|
358
|
+
plugins: { tailwind: tailwindPlugin },
|
|
359
|
+
settings: { tailwindcss: resolved.settings },
|
|
360
|
+
rules: {
|
|
361
|
+
...renamePluginsInRules(inheritedRules, { "better-tailwindcss": "tailwind" }),
|
|
362
|
+
"tailwind/no-unregistered-classes": "off",
|
|
363
|
+
"tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
|
|
364
|
+
...resolved.overrides
|
|
365
|
+
}
|
|
366
|
+
}];
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/configs/typescript.ts
|
|
370
|
+
const typescriptDefaults = { files: [tsGlob] };
|
|
371
|
+
/**
|
|
372
|
+
* Typescript linting via `typescript-eslint`.
|
|
373
|
+
* @param options - TypeScript configuration options
|
|
374
|
+
* @returns Array of TypeScript ESLint config items
|
|
375
|
+
*/
|
|
376
|
+
async function typescript(options) {
|
|
377
|
+
const resolved = defu(options, typescriptDefaults);
|
|
378
|
+
const tsEsLint = await importModule(import("typescript-eslint"));
|
|
379
|
+
const inheritedRules = Object.assign({}, ...[...tsEsLint.configs.recommended, ...tsEsLint.configs.strict].map((config) => config?.rules || {}));
|
|
380
|
+
return [{
|
|
381
|
+
name: "favorodera/typescript",
|
|
382
|
+
plugins: { ts: tsEsLint.plugin },
|
|
383
|
+
languageOptions: {
|
|
384
|
+
parser: tsEsLint.parser,
|
|
385
|
+
parserOptions: { sourceType: "module" }
|
|
386
|
+
},
|
|
387
|
+
files: resolved.files,
|
|
388
|
+
rules: {
|
|
389
|
+
...renamePluginsInRules(inheritedRules, { "@typescript-eslint": "ts" }),
|
|
390
|
+
"ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
|
|
391
|
+
"ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
|
|
392
|
+
"ts/array-type": ["error", { default: "array" }],
|
|
628
393
|
...resolved.overrides
|
|
629
394
|
}
|
|
630
395
|
}];
|
|
@@ -639,25 +404,28 @@ async function javascript(options) {
|
|
|
639
404
|
function factory(options = {}) {
|
|
640
405
|
const configs = [];
|
|
641
406
|
configs.push(ignores(options.ignores));
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
if (markdownOptions) configs.push(markdown(markdownOptions));
|
|
657
|
-
if (javascriptOptions) configs.push(javascript(javascriptOptions));
|
|
407
|
+
const configFunctions = {
|
|
408
|
+
vue,
|
|
409
|
+
typescript,
|
|
410
|
+
stylistic,
|
|
411
|
+
tailwind,
|
|
412
|
+
imports,
|
|
413
|
+
markdown,
|
|
414
|
+
javascript
|
|
415
|
+
};
|
|
416
|
+
for (const [key, configFunction] of Object.entries(configFunctions)) {
|
|
417
|
+
const configOption = options[key];
|
|
418
|
+
const resolved = resolveOptions(configOption ?? true, {});
|
|
419
|
+
if (resolved) configs.push(configFunction(resolved));
|
|
420
|
+
}
|
|
658
421
|
let composer = new FlatConfigComposer();
|
|
659
|
-
composer = composer.append(...configs)
|
|
422
|
+
composer = composer.append(...configs).renamePlugins({
|
|
423
|
+
"better-tailwindcss": "tailwind",
|
|
424
|
+
"@typescript-eslint": "ts",
|
|
425
|
+
"markdown": "md",
|
|
426
|
+
"import-lite": "import"
|
|
427
|
+
});
|
|
660
428
|
return composer;
|
|
661
429
|
}
|
|
662
430
|
//#endregion
|
|
663
|
-
export { factory,
|
|
431
|
+
export { factory, importModule };
|