@favorodera/eslint-config 0.0.3 → 0.0.5
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 +148 -1
- package/dist/index.cjs +569 -316
- package/dist/index.d.cts +6658 -1423
- package/dist/index.d.mts +6656 -1421
- package/dist/index.mjs +568 -315
- package/package.json +6 -2
package/dist/index.mjs
CHANGED
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
import { FlatConfigComposer, renamePluginsInRules } from "eslint-flat-config-utils";
|
|
2
2
|
import { defu } from "defu";
|
|
3
|
+
import globals from "globals";
|
|
3
4
|
import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
|
|
4
5
|
import vueBlocksProcessor from "eslint-processor-vue-blocks";
|
|
5
|
-
import globals from "globals";
|
|
6
6
|
//#region src/globs.ts
|
|
7
|
+
/** Glob pattern for matching JavaScript files */
|
|
7
8
|
const jsGlob = "**/*.{js,cjs,mjs}";
|
|
9
|
+
/** Glob pattern for matching TypeScript files */
|
|
8
10
|
const tsGlob = "**/*.{ts,cts,mts}";
|
|
11
|
+
/** Glob pattern for matching Vue single-file components */
|
|
9
12
|
const vueGlob = "**/*.vue";
|
|
13
|
+
/** Glob pattern for matching Markdown files */
|
|
10
14
|
const mdGlob = "**/*.md";
|
|
15
|
+
/** Glob pattern for matching virtual files extracted from Markdown */
|
|
11
16
|
const mdInMdGlob = "**/*.md/*.md";
|
|
17
|
+
/** Glob pattern for matching code blocks embedded in Markdown files */
|
|
12
18
|
const codeInMdGlob = "**/*.md/**/*.{js,cjs,mjs,ts,cts,mts,vue}";
|
|
19
|
+
/** Glob pattern for matching JSON files */
|
|
13
20
|
const jsonGlob = "**/*.json";
|
|
21
|
+
/** Glob pattern for matching JSON5 files */
|
|
14
22
|
const json5Glob = "**/*.json5";
|
|
23
|
+
/** Glob pattern for matching JSON with Comments files */
|
|
15
24
|
const jsoncGlob = "**/*.jsonc";
|
|
25
|
+
/** Glob patterns for matching TypeScript configuration files */
|
|
16
26
|
const tsConfigGlob = ["**/tsconfig.json", "**/tsconfig.*.json"];
|
|
27
|
+
/** Glob pattern for matching package.json files */
|
|
17
28
|
const packageJsonGlob = "**/package.json";
|
|
18
|
-
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/configs/ignores.ts
|
|
31
|
+
const defaultPatterns = [
|
|
19
32
|
"**/node_modules/**",
|
|
20
33
|
"**/dist/**",
|
|
21
34
|
"**/package-lock.json",
|
|
@@ -52,17 +65,36 @@ const ignoresGlob = [
|
|
|
52
65
|
"**/.agents",
|
|
53
66
|
"**/.*/skills"
|
|
54
67
|
];
|
|
68
|
+
/**
|
|
69
|
+
* Globs for ignoring files and directories from ESLint scanning.
|
|
70
|
+
* @param patterns Additional ignore patterns or a function to modify the defaults.
|
|
71
|
+
* @returns An array containing the ignore flat config item.
|
|
72
|
+
*/
|
|
73
|
+
function ignores(patterns = []) {
|
|
74
|
+
return [{
|
|
75
|
+
ignores: typeof patterns === "function" ? patterns(defaultPatterns) : [...defaultPatterns, ...patterns],
|
|
76
|
+
name: "favorodera/ignores"
|
|
77
|
+
}];
|
|
78
|
+
}
|
|
55
79
|
//#endregion
|
|
56
80
|
//#region src/utils.ts
|
|
57
81
|
/**
|
|
82
|
+
* Extracts and merges the rules from multiple ESLint configuration arrays.
|
|
83
|
+
* @param configArrays Rest parameter representing multiple arrays of ESLint flat config items.
|
|
84
|
+
* @returns A single object containing all the merged rules from the provided configurations.
|
|
85
|
+
*/
|
|
86
|
+
function extractRules(...configArrays) {
|
|
87
|
+
return Object.assign({}, ...configArrays.flat().map((config) => config?.rules || {}));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
58
90
|
* Resolves a module (or a promise of one) and returns its default export
|
|
59
91
|
* if present, otherwise returns the module itself.
|
|
60
92
|
*
|
|
61
93
|
* Handles both ESM modules (which wrap exports under `.default`) and
|
|
62
94
|
* CJS / plain-object modules uniformly.
|
|
63
|
-
*
|
|
64
|
-
* @param module
|
|
65
|
-
* @returns The `.default` export if it exists, otherwise the module itself
|
|
95
|
+
* @template TModule The type of the module being imported.
|
|
96
|
+
* @param module A module or a promise that resolves to one.
|
|
97
|
+
* @returns The `.default` export if it exists, otherwise the module itself.
|
|
66
98
|
*/
|
|
67
99
|
async function importModule(module) {
|
|
68
100
|
const resolved = await module;
|
|
@@ -72,106 +104,15 @@ async function importModule(module) {
|
|
|
72
104
|
/**
|
|
73
105
|
* Normalize boolean or options value into merged options or null.
|
|
74
106
|
* Returns null when the input is false or undefined.
|
|
75
|
-
*
|
|
76
|
-
* @param value
|
|
77
|
-
* @param defaults
|
|
78
|
-
* @returns merged options or false
|
|
107
|
+
* @template TOptions The type of the options object.
|
|
108
|
+
* @param value The configuration value, which can be a boolean, an options object, or undefined.
|
|
109
|
+
* @param defaults The default options to merge with if `value` is true or an object.
|
|
110
|
+
* @returns The merged options object, or false if the feature is disabled.
|
|
79
111
|
*/
|
|
80
112
|
function resolveOptions(value, defaults) {
|
|
81
113
|
if (!value) return false;
|
|
82
114
|
return defu(value === true ? {} : value, defaults);
|
|
83
115
|
}
|
|
84
|
-
function extractRules(...configArrays) {
|
|
85
|
-
return Object.assign({}, ...configArrays.flat().map((config) => config?.rules || {}));
|
|
86
|
-
}
|
|
87
|
-
//#endregion
|
|
88
|
-
//#region src/configs/vue.ts
|
|
89
|
-
const sfcBlocksDefaults = { blocks: {
|
|
90
|
-
styles: true,
|
|
91
|
-
customBlocks: true,
|
|
92
|
-
template: false
|
|
93
|
-
} };
|
|
94
|
-
const vueDefaults = {
|
|
95
|
-
files: [vueGlob],
|
|
96
|
-
sfcBlocks: sfcBlocksDefaults
|
|
97
|
-
};
|
|
98
|
-
async function vue(options) {
|
|
99
|
-
const resolved = defu(options, vueDefaults);
|
|
100
|
-
const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
|
|
101
|
-
const [vuePlugin, vueParser, tsEsLint] = await Promise.all([
|
|
102
|
-
importModule(import("eslint-plugin-vue")),
|
|
103
|
-
importModule(import("vue-eslint-parser")),
|
|
104
|
-
importModule(import("typescript-eslint"))
|
|
105
|
-
]);
|
|
106
|
-
const baseRules = extractRules(vuePlugin.configs["flat/essential"], vuePlugin.configs["flat/strongly-recommended"], vuePlugin.configs["flat/recommended"]);
|
|
107
|
-
const processor = sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]);
|
|
108
|
-
return [{
|
|
109
|
-
name: "favorodera/vue/setup",
|
|
110
|
-
plugins: { vue: vuePlugin },
|
|
111
|
-
languageOptions: { globals: {
|
|
112
|
-
computed: "readonly",
|
|
113
|
-
defineEmits: "readonly",
|
|
114
|
-
defineExpose: "readonly",
|
|
115
|
-
defineProps: "readonly",
|
|
116
|
-
onMounted: "readonly",
|
|
117
|
-
onUnmounted: "readonly",
|
|
118
|
-
reactive: "readonly",
|
|
119
|
-
ref: "readonly",
|
|
120
|
-
shallowReactive: "readonly",
|
|
121
|
-
shallowRef: "readonly",
|
|
122
|
-
toRef: "readonly",
|
|
123
|
-
toRefs: "readonly",
|
|
124
|
-
watch: "readonly",
|
|
125
|
-
watchEffect: "readonly"
|
|
126
|
-
} }
|
|
127
|
-
}, {
|
|
128
|
-
name: "favorodera/vue/rules",
|
|
129
|
-
files: resolved.files,
|
|
130
|
-
languageOptions: {
|
|
131
|
-
parser: vueParser,
|
|
132
|
-
parserOptions: {
|
|
133
|
-
parser: tsEsLint.parser,
|
|
134
|
-
extraFileExtensions: [".vue"],
|
|
135
|
-
sourceType: "module"
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
processor,
|
|
139
|
-
rules: {
|
|
140
|
-
...baseRules,
|
|
141
|
-
"vue/block-order": ["error", { order: [
|
|
142
|
-
"script",
|
|
143
|
-
"template",
|
|
144
|
-
"style"
|
|
145
|
-
] }],
|
|
146
|
-
"vue/component-name-in-template-casing": ["error", "PascalCase"],
|
|
147
|
-
"vue/component-options-name-casing": ["error", "PascalCase"],
|
|
148
|
-
"vue/multi-word-component-names": "off",
|
|
149
|
-
"vue/block-tag-newline": ["error", {
|
|
150
|
-
multiline: "ignore",
|
|
151
|
-
singleline: "ignore"
|
|
152
|
-
}],
|
|
153
|
-
"vue/multiline-html-element-content-newline": ["error", {
|
|
154
|
-
allowEmptyLines: true,
|
|
155
|
-
ignores: ["pre", "textarea"]
|
|
156
|
-
}],
|
|
157
|
-
...resolved.overrides
|
|
158
|
-
}
|
|
159
|
-
}];
|
|
160
|
-
}
|
|
161
|
-
//#endregion
|
|
162
|
-
//#region src/configs/ignores.ts
|
|
163
|
-
const defaultPatterns = ignoresGlob;
|
|
164
|
-
/**
|
|
165
|
-
* Globs for ignoring files and directories from ESLint scanning.
|
|
166
|
-
* @param patterns - Additional ignore patterns or a function to modify the defaults.
|
|
167
|
-
* @returns An array containing the ignore flat config item.
|
|
168
|
-
*/
|
|
169
|
-
function ignores(patterns = []) {
|
|
170
|
-
return [{
|
|
171
|
-
name: "favorodera/ignores",
|
|
172
|
-
ignores: typeof patterns === "function" ? patterns(defaultPatterns) : [...defaultPatterns, ...patterns]
|
|
173
|
-
}];
|
|
174
|
-
}
|
|
175
116
|
//#endregion
|
|
176
117
|
//#region src/configs/imports.ts
|
|
177
118
|
const importsDefaults = { files: [
|
|
@@ -179,6 +120,12 @@ const importsDefaults = { files: [
|
|
|
179
120
|
tsGlob,
|
|
180
121
|
vueGlob
|
|
181
122
|
] };
|
|
123
|
+
/**
|
|
124
|
+
* Constructs the flat config items for imports linting, providing plugin setup and
|
|
125
|
+
* specific rules to enforce consistent import ordering and unused variable checks.
|
|
126
|
+
* @param options Configuration options for imports linting.
|
|
127
|
+
* @returns Promise resolving to imports ESLint config items.
|
|
128
|
+
*/
|
|
182
129
|
async function imports(options) {
|
|
183
130
|
const resolved = defu(options, importsDefaults);
|
|
184
131
|
const [importPlugin, unusedImportsPlugin] = await Promise.all([importModule(import("eslint-plugin-import-lite")), importModule(import("eslint-plugin-unused-imports"))]);
|
|
@@ -190,16 +137,16 @@ async function imports(options) {
|
|
|
190
137
|
"unused-imports": unusedImportsPlugin
|
|
191
138
|
}
|
|
192
139
|
}, {
|
|
193
|
-
name: "favorodera/imports/rules",
|
|
194
140
|
files: resolved.files,
|
|
141
|
+
name: "favorodera/imports/rules",
|
|
195
142
|
rules: {
|
|
196
143
|
...renamePluginsInRules(baseRules, { "import-lite": "import" }),
|
|
197
|
-
"import/consistent-type-specifier-style": ["error", "top-level"],
|
|
144
|
+
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
|
|
198
145
|
"import/first": "error",
|
|
146
|
+
"import/newline-after-import": ["error", { count: 1 }],
|
|
199
147
|
"import/no-duplicates": "error",
|
|
200
148
|
"import/no-mutable-exports": "error",
|
|
201
149
|
"import/no-named-default": "error",
|
|
202
|
-
"import/newline-after-import": ["error", { count: 1 }],
|
|
203
150
|
"unused-imports/no-unused-imports": "error",
|
|
204
151
|
"unused-imports/no-unused-vars": ["error", {
|
|
205
152
|
args: "after-used",
|
|
@@ -220,18 +167,17 @@ const javascriptDefaults = { files: [
|
|
|
220
167
|
vueGlob
|
|
221
168
|
] };
|
|
222
169
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
* @
|
|
170
|
+
* Constructs the flat config items for core JavaScript linting, setting up the required
|
|
171
|
+
* language options, globals, and recommended baseline rules.
|
|
172
|
+
* @param options Javascript configuration options.
|
|
173
|
+
* @returns Promise resolving to javascript ESLint config items.
|
|
226
174
|
*/
|
|
227
175
|
async function javascript(options) {
|
|
228
176
|
const resolved = defu(options, javascriptDefaults);
|
|
229
177
|
const baseRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
|
|
230
178
|
return [{
|
|
231
|
-
name: "favorodera/javascript/setup",
|
|
232
179
|
languageOptions: {
|
|
233
180
|
ecmaVersion: "latest",
|
|
234
|
-
sourceType: "module",
|
|
235
181
|
globals: {
|
|
236
182
|
...globals.browser,
|
|
237
183
|
...globals.es2021,
|
|
@@ -239,12 +185,14 @@ async function javascript(options) {
|
|
|
239
185
|
document: "readonly",
|
|
240
186
|
navigator: "readonly",
|
|
241
187
|
window: "readonly"
|
|
242
|
-
}
|
|
188
|
+
},
|
|
189
|
+
sourceType: "module"
|
|
243
190
|
},
|
|
244
|
-
linterOptions: { reportUnusedDisableDirectives: true }
|
|
191
|
+
linterOptions: { reportUnusedDisableDirectives: true },
|
|
192
|
+
name: "favorodera/javascript/setup"
|
|
245
193
|
}, {
|
|
246
|
-
name: "favorodera/javascript/rules",
|
|
247
194
|
files: resolved.files,
|
|
195
|
+
name: "favorodera/javascript/rules",
|
|
248
196
|
rules: {
|
|
249
197
|
...baseRules,
|
|
250
198
|
"accessor-pairs": ["error", {
|
|
@@ -258,189 +206,50 @@ async function javascript(options) {
|
|
|
258
206
|
}];
|
|
259
207
|
}
|
|
260
208
|
//#endregion
|
|
261
|
-
//#region src/configs/
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const resolved = defu(options, markdownDefaults);
|
|
268
|
-
const markdownPlugin = await importModule(import("@eslint/markdown"));
|
|
269
|
-
const baseRules = extractRules(markdownPlugin.configs.recommended);
|
|
270
|
-
return [
|
|
271
|
-
{
|
|
272
|
-
name: "favorodera/markdown/setup",
|
|
273
|
-
plugins: { md: markdownPlugin }
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
name: "favorodera/markdown/rules",
|
|
277
|
-
files: resolved.files,
|
|
278
|
-
language: resolved.gfm ? "md/gfm" : "md/commonmark",
|
|
279
|
-
ignores: [mdInMdGlob],
|
|
280
|
-
processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
|
|
281
|
-
rules: {
|
|
282
|
-
...renamePluginsInRules(baseRules, { markdown: "md" }),
|
|
283
|
-
"md/fenced-code-language": "off",
|
|
284
|
-
"md/no-missing-label-refs": "off",
|
|
285
|
-
...resolved.overrides
|
|
286
|
-
}
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
name: "favorodera/markdown/disables/code",
|
|
290
|
-
files: [codeInMdGlob],
|
|
291
|
-
languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
|
|
292
|
-
rules: {
|
|
293
|
-
"no-alert": "off",
|
|
294
|
-
"no-console": "off",
|
|
295
|
-
"no-labels": "off",
|
|
296
|
-
"no-lone-blocks": "off",
|
|
297
|
-
"no-restricted-syntax": "off",
|
|
298
|
-
"no-undef": "off",
|
|
299
|
-
"no-unused-expressions": "off",
|
|
300
|
-
"no-unused-labels": "off",
|
|
301
|
-
"no-unused-vars": "off",
|
|
302
|
-
"node/prefer-global/process": "off",
|
|
303
|
-
"style/comma-dangle": "off",
|
|
304
|
-
"style/eol-last": "off",
|
|
305
|
-
"style/padding-line-between-statements": "off",
|
|
306
|
-
"ts/consistent-type-imports": "off",
|
|
307
|
-
"ts/explicit-function-return-type": "off",
|
|
308
|
-
"ts/no-namespace": "off",
|
|
309
|
-
"ts/no-redeclare": "off",
|
|
310
|
-
"ts/no-require-imports": "off",
|
|
311
|
-
"ts/no-unused-expressions": "off",
|
|
312
|
-
"ts/no-unused-vars": "off",
|
|
313
|
-
"ts/no-use-before-define": "off",
|
|
314
|
-
"unicode-bom": "off",
|
|
315
|
-
"unused-imports/no-unused-imports": "off",
|
|
316
|
-
"unused-imports/no-unused-vars": "off"
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
];
|
|
320
|
-
}
|
|
321
|
-
//#endregion
|
|
322
|
-
//#region src/configs/stylistic.ts
|
|
323
|
-
const stylisticDefaults = {
|
|
324
|
-
settings: {
|
|
325
|
-
indent: 2,
|
|
326
|
-
experimental: false,
|
|
327
|
-
quotes: "single",
|
|
328
|
-
semi: false,
|
|
329
|
-
jsx: false
|
|
330
|
-
},
|
|
331
|
-
files: [
|
|
332
|
-
jsGlob,
|
|
333
|
-
tsGlob,
|
|
334
|
-
vueGlob
|
|
335
|
-
]
|
|
336
|
-
};
|
|
337
|
-
async function stylistic(options) {
|
|
338
|
-
const resolved = defu(options, stylisticDefaults);
|
|
339
|
-
const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
|
|
340
|
-
const baseRules = stylePlugin.configs.customize({
|
|
341
|
-
pluginName: "style",
|
|
342
|
-
...resolved.settings
|
|
343
|
-
})?.rules || {};
|
|
344
|
-
return [{
|
|
345
|
-
name: "favorodera/stylistic/setup",
|
|
346
|
-
plugins: { style: stylePlugin }
|
|
347
|
-
}, {
|
|
348
|
-
name: "favorodera/stylistic/rules",
|
|
349
|
-
files: resolved.files,
|
|
350
|
-
rules: {
|
|
351
|
-
...baseRules,
|
|
352
|
-
"style/quotes": [
|
|
353
|
-
"error",
|
|
354
|
-
"single",
|
|
355
|
-
{ avoidEscape: true }
|
|
356
|
-
],
|
|
357
|
-
"style/no-multiple-empty-lines": ["error", {
|
|
358
|
-
max: 2,
|
|
359
|
-
maxEOF: 2,
|
|
360
|
-
maxBOF: 0
|
|
361
|
-
}],
|
|
362
|
-
"style/padded-blocks": "off",
|
|
363
|
-
"style/no-trailing-spaces": ["error", { skipBlankLines: true }],
|
|
364
|
-
"style/brace-style": "off",
|
|
365
|
-
"style/generator-star-spacing": ["error", {
|
|
366
|
-
after: true,
|
|
367
|
-
before: false
|
|
368
|
-
}],
|
|
369
|
-
"style/yield-star-spacing": ["error", {
|
|
370
|
-
after: true,
|
|
371
|
-
before: false
|
|
372
|
-
}],
|
|
373
|
-
...resolved.overrides
|
|
374
|
-
}
|
|
375
|
-
}];
|
|
376
|
-
}
|
|
377
|
-
//#endregion
|
|
378
|
-
//#region src/configs/tailwind.ts
|
|
379
|
-
const tailwindDefaults = {
|
|
380
|
-
files: [
|
|
381
|
-
jsGlob,
|
|
382
|
-
tsGlob,
|
|
383
|
-
vueGlob
|
|
384
|
-
],
|
|
385
|
-
settings: { detectComponentClasses: true }
|
|
386
|
-
};
|
|
209
|
+
//#region src/configs/jsdoc.ts
|
|
210
|
+
const jsdocDefaults = { files: [
|
|
211
|
+
jsGlob,
|
|
212
|
+
tsGlob,
|
|
213
|
+
vueGlob
|
|
214
|
+
] };
|
|
387
215
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* @
|
|
216
|
+
* Constructs the flat config items for JSDoc linting, ensuring comments follow
|
|
217
|
+
* proper styling, parameter checks, and types alignment.
|
|
218
|
+
* @param options JSDoc configuration options.
|
|
219
|
+
* @returns Promise resolving to JSDoc ESLint config items.
|
|
391
220
|
*/
|
|
392
|
-
async function
|
|
393
|
-
const resolved = defu(options,
|
|
394
|
-
const
|
|
221
|
+
async function jsdoc(options) {
|
|
222
|
+
const resolved = defu(options, jsdocDefaults);
|
|
223
|
+
const jsdocPlugin = await importModule(import("eslint-plugin-jsdoc"));
|
|
395
224
|
const baseRules = {
|
|
396
|
-
...
|
|
397
|
-
...
|
|
225
|
+
...jsdocPlugin.configs["flat/recommended-typescript-error"]?.rules,
|
|
226
|
+
...jsdocPlugin.configs["flat/stylistic-typescript-error"]?.rules
|
|
398
227
|
};
|
|
399
228
|
return [{
|
|
400
|
-
name: "favorodera/
|
|
401
|
-
plugins: {
|
|
402
|
-
settings: { tailwindcss: resolved.settings }
|
|
229
|
+
name: "favorodera/jsdoc/setup",
|
|
230
|
+
plugins: { jsdoc: jsdocPlugin }
|
|
403
231
|
}, {
|
|
404
|
-
name: "favorodera/tailwind/rules",
|
|
405
232
|
files: resolved.files,
|
|
233
|
+
name: "favorodera/tailwind/rules",
|
|
406
234
|
rules: {
|
|
407
|
-
...
|
|
408
|
-
"
|
|
409
|
-
"
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const baseRules = extractRules(tsEsLint.configs.recommended, tsEsLint.configs.strict);
|
|
426
|
-
return [{
|
|
427
|
-
name: "favorodera/typescript/setup",
|
|
428
|
-
plugins: { ts: tsEsLint.plugin }
|
|
429
|
-
}, {
|
|
430
|
-
name: "favorodera/typescript/rules",
|
|
431
|
-
files: resolved.files,
|
|
432
|
-
languageOptions: {
|
|
433
|
-
parser: tsEsLint.parser,
|
|
434
|
-
parserOptions: { sourceType: "module" }
|
|
435
|
-
},
|
|
436
|
-
rules: {
|
|
437
|
-
...renamePluginsInRules(baseRules, { "@typescript-eslint": "ts" }),
|
|
438
|
-
"ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
|
|
439
|
-
"ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
|
|
440
|
-
"ts/array-type": ["error", {
|
|
441
|
-
default: "generic",
|
|
442
|
-
readonly: "generic"
|
|
443
|
-
}],
|
|
235
|
+
...baseRules,
|
|
236
|
+
"jsdoc/check-access": "warn",
|
|
237
|
+
"jsdoc/check-alignment": "warn",
|
|
238
|
+
"jsdoc/check-param-names": "warn",
|
|
239
|
+
"jsdoc/check-property-names": "warn",
|
|
240
|
+
"jsdoc/check-types": "warn",
|
|
241
|
+
"jsdoc/empty-tags": "warn",
|
|
242
|
+
"jsdoc/implements-on-classes": "warn",
|
|
243
|
+
"jsdoc/multiline-blocks": "warn",
|
|
244
|
+
"jsdoc/no-defaults": "warn",
|
|
245
|
+
"jsdoc/no-multi-asterisks": "warn",
|
|
246
|
+
"jsdoc/require-param-name": "warn",
|
|
247
|
+
"jsdoc/require-property": "warn",
|
|
248
|
+
"jsdoc/require-property-description": "warn",
|
|
249
|
+
"jsdoc/require-property-name": "warn",
|
|
250
|
+
"jsdoc/require-returns-check": "warn",
|
|
251
|
+
"jsdoc/require-returns-description": "warn",
|
|
252
|
+
"jsdoc/require-yields-check": "warn",
|
|
444
253
|
...resolved.overrides
|
|
445
254
|
}
|
|
446
255
|
}];
|
|
@@ -452,6 +261,12 @@ const jsoncDefaults = { files: [
|
|
|
452
261
|
jsoncGlob,
|
|
453
262
|
jsonGlob
|
|
454
263
|
] };
|
|
264
|
+
/**
|
|
265
|
+
* Constructs the flat config items for JSON, JSON5, and JSONC linting, setting up
|
|
266
|
+
* the custom parser, rule validations, and sorting rules for package.json/tsconfig.json.
|
|
267
|
+
* @param options JSONC configuration options.
|
|
268
|
+
* @returns Promise resolving to JSONC ESLint config items.
|
|
269
|
+
*/
|
|
455
270
|
async function jsonc(options) {
|
|
456
271
|
const resolved = defu(options, jsoncDefaults);
|
|
457
272
|
return [
|
|
@@ -460,10 +275,18 @@ async function jsonc(options) {
|
|
|
460
275
|
plugins: { jsonc: await importModule(import("eslint-plugin-jsonc")) }
|
|
461
276
|
},
|
|
462
277
|
{
|
|
463
|
-
name: "favorodera/jsonc/rules",
|
|
464
278
|
files: resolved.files,
|
|
465
279
|
language: "jsonc/x",
|
|
280
|
+
name: "favorodera/jsonc/rules",
|
|
466
281
|
rules: {
|
|
282
|
+
"jsonc/array-bracket-spacing": ["error", "never"],
|
|
283
|
+
"jsonc/comma-dangle": ["error", "never"],
|
|
284
|
+
"jsonc/comma-style": ["error", "last"],
|
|
285
|
+
"jsonc/indent": ["error", 2],
|
|
286
|
+
"jsonc/key-spacing": ["error", {
|
|
287
|
+
afterColon: true,
|
|
288
|
+
beforeColon: false
|
|
289
|
+
}],
|
|
467
290
|
"jsonc/no-bigint-literals": "error",
|
|
468
291
|
"jsonc/no-binary-expression": "error",
|
|
469
292
|
"jsonc/no-binary-numeric-literals": "error",
|
|
@@ -487,17 +310,6 @@ async function jsonc(options) {
|
|
|
487
310
|
"jsonc/no-undefined-value": "error",
|
|
488
311
|
"jsonc/no-unicode-codepoint-escapes": "error",
|
|
489
312
|
"jsonc/no-useless-escape": "error",
|
|
490
|
-
"jsonc/space-unary-ops": "error",
|
|
491
|
-
"jsonc/valid-json-number": "error",
|
|
492
|
-
"jsonc/vue-custom-block/no-parsing-error": "error",
|
|
493
|
-
"jsonc/array-bracket-spacing": ["error", "never"],
|
|
494
|
-
"jsonc/comma-dangle": ["error", "never"],
|
|
495
|
-
"jsonc/comma-style": ["error", "last"],
|
|
496
|
-
"jsonc/indent": ["error", 2],
|
|
497
|
-
"jsonc/key-spacing": ["error", {
|
|
498
|
-
afterColon: true,
|
|
499
|
-
beforeColon: false
|
|
500
|
-
}],
|
|
501
313
|
"jsonc/object-curly-newline": ["error", {
|
|
502
314
|
consistent: true,
|
|
503
315
|
multiline: true
|
|
@@ -506,12 +318,15 @@ async function jsonc(options) {
|
|
|
506
318
|
"jsonc/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
|
|
507
319
|
"jsonc/quote-props": "error",
|
|
508
320
|
"jsonc/quotes": "error",
|
|
321
|
+
"jsonc/space-unary-ops": "error",
|
|
322
|
+
"jsonc/valid-json-number": "error",
|
|
323
|
+
"jsonc/vue-custom-block/no-parsing-error": "error",
|
|
509
324
|
...resolved.overrides
|
|
510
325
|
}
|
|
511
326
|
},
|
|
512
327
|
{
|
|
513
|
-
name: "favorodera/jsonc/sort/package-json",
|
|
514
328
|
files: [packageJsonGlob],
|
|
329
|
+
name: "favorodera/jsonc/sort/package-json",
|
|
515
330
|
rules: {
|
|
516
331
|
"jsonc/sort-array-values": ["error", {
|
|
517
332
|
order: { type: "asc" },
|
|
@@ -579,11 +394,11 @@ async function jsonc(options) {
|
|
|
579
394
|
},
|
|
580
395
|
{
|
|
581
396
|
order: { type: "asc" },
|
|
582
|
-
pathPattern:
|
|
397
|
+
pathPattern: String.raw`^workspaces\.catalog$`
|
|
583
398
|
},
|
|
584
399
|
{
|
|
585
400
|
order: { type: "asc" },
|
|
586
|
-
pathPattern:
|
|
401
|
+
pathPattern: String.raw`^workspaces\.catalogs\.[^.]+$`
|
|
587
402
|
},
|
|
588
403
|
{
|
|
589
404
|
order: [
|
|
@@ -613,8 +428,8 @@ async function jsonc(options) {
|
|
|
613
428
|
}
|
|
614
429
|
},
|
|
615
430
|
{
|
|
616
|
-
name: "favorodera/jsonc/sort/tsconfig-json",
|
|
617
431
|
files: tsConfigGlob,
|
|
432
|
+
name: "favorodera/jsonc/sort/tsconfig-json",
|
|
618
433
|
rules: { "jsonc/sort-keys": [
|
|
619
434
|
"error",
|
|
620
435
|
{
|
|
@@ -729,24 +544,461 @@ async function jsonc(options) {
|
|
|
729
544
|
];
|
|
730
545
|
}
|
|
731
546
|
//#endregion
|
|
547
|
+
//#region src/configs/markdown.ts
|
|
548
|
+
const markdownDefaults = {
|
|
549
|
+
files: [mdGlob],
|
|
550
|
+
gfm: true
|
|
551
|
+
};
|
|
552
|
+
/**
|
|
553
|
+
* Constructs the flat config items for Markdown linting, extracting and linting
|
|
554
|
+
* embedded code blocks within the document according to specified rules.
|
|
555
|
+
* @param options Markdown configuration options.
|
|
556
|
+
* @returns Promise resolving to Markdown ESLint config items.
|
|
557
|
+
*/
|
|
558
|
+
async function markdown(options) {
|
|
559
|
+
const resolved = defu(options, markdownDefaults);
|
|
560
|
+
const markdownPlugin = await importModule(import("@eslint/markdown"));
|
|
561
|
+
const baseRules = extractRules(markdownPlugin.configs.recommended);
|
|
562
|
+
return [
|
|
563
|
+
{
|
|
564
|
+
name: "favorodera/markdown/setup",
|
|
565
|
+
plugins: { md: markdownPlugin }
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
files: resolved.files,
|
|
569
|
+
ignores: [mdInMdGlob],
|
|
570
|
+
language: resolved.gfm ? "md/gfm" : "md/commonmark",
|
|
571
|
+
name: "favorodera/markdown/rules",
|
|
572
|
+
processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
|
|
573
|
+
rules: {
|
|
574
|
+
...renamePluginsInRules(baseRules, { markdown: "md" }),
|
|
575
|
+
"md/fenced-code-language": "off",
|
|
576
|
+
"md/no-missing-label-refs": "off",
|
|
577
|
+
...resolved.overrides
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
files: [codeInMdGlob],
|
|
582
|
+
languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
|
|
583
|
+
name: "favorodera/markdown/disables/code",
|
|
584
|
+
rules: {
|
|
585
|
+
"no-alert": "off",
|
|
586
|
+
"no-console": "off",
|
|
587
|
+
"no-labels": "off",
|
|
588
|
+
"no-lone-blocks": "off",
|
|
589
|
+
"no-restricted-syntax": "off",
|
|
590
|
+
"no-undef": "off",
|
|
591
|
+
"no-unused-expressions": "off",
|
|
592
|
+
"no-unused-labels": "off",
|
|
593
|
+
"no-unused-vars": "off",
|
|
594
|
+
"node/prefer-global/process": "off",
|
|
595
|
+
"style/comma-dangle": "off",
|
|
596
|
+
"style/eol-last": "off",
|
|
597
|
+
"style/padding-line-between-statements": "off",
|
|
598
|
+
"ts/consistent-type-imports": "off",
|
|
599
|
+
"ts/explicit-function-return-type": "off",
|
|
600
|
+
"ts/no-namespace": "off",
|
|
601
|
+
"ts/no-redeclare": "off",
|
|
602
|
+
"ts/no-require-imports": "off",
|
|
603
|
+
"ts/no-unused-expressions": "off",
|
|
604
|
+
"ts/no-unused-vars": "off",
|
|
605
|
+
"ts/no-use-before-define": "off",
|
|
606
|
+
"unicode-bom": "off",
|
|
607
|
+
"unused-imports/no-unused-imports": "off",
|
|
608
|
+
"unused-imports/no-unused-vars": "off"
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
];
|
|
612
|
+
}
|
|
613
|
+
//#endregion
|
|
614
|
+
//#region src/configs/node.ts
|
|
615
|
+
const nodeDefaults = { files: [
|
|
616
|
+
jsGlob,
|
|
617
|
+
tsGlob,
|
|
618
|
+
vueGlob
|
|
619
|
+
] };
|
|
620
|
+
/**
|
|
621
|
+
* Constructs the flat config items for Node.js linting, providing rules
|
|
622
|
+
* to enforce best practices for Node.js environments.
|
|
623
|
+
* @param options Node configuration options.
|
|
624
|
+
* @returns Promise resolving to Node ESLint config items.
|
|
625
|
+
*/
|
|
626
|
+
async function node(options) {
|
|
627
|
+
const resolved = defu(options, nodeDefaults);
|
|
628
|
+
const nodePlugin = await importModule(import("eslint-plugin-n"));
|
|
629
|
+
const baseRules = nodePlugin.configs?.["flat/recommended"]?.rules || {};
|
|
630
|
+
return [{
|
|
631
|
+
name: "favorodera/node/setup",
|
|
632
|
+
plugins: { node: nodePlugin }
|
|
633
|
+
}, {
|
|
634
|
+
files: resolved.files,
|
|
635
|
+
name: "favorodera/node/rules",
|
|
636
|
+
rules: {
|
|
637
|
+
...renamePluginsInRules(baseRules, { n: "node" }),
|
|
638
|
+
"node/handle-callback-err": ["error", "^(err|error)$"],
|
|
639
|
+
"node/no-deprecated-api": "error",
|
|
640
|
+
"node/no-exports-assign": "error",
|
|
641
|
+
"node/no-missing-import": "off",
|
|
642
|
+
"node/no-new-require": "error",
|
|
643
|
+
"node/no-path-concat": "error",
|
|
644
|
+
"node/no-unpublished-import": "off",
|
|
645
|
+
"node/prefer-global/buffer": ["error", "never"],
|
|
646
|
+
"node/prefer-global/process": ["error", "never"],
|
|
647
|
+
"node/process-exit-as-throw": "error",
|
|
648
|
+
...resolved.overrides
|
|
649
|
+
}
|
|
650
|
+
}];
|
|
651
|
+
}
|
|
652
|
+
//#endregion
|
|
653
|
+
//#region src/configs/perfectionist.ts
|
|
654
|
+
const perfectionistDefaults = { files: [
|
|
655
|
+
jsGlob,
|
|
656
|
+
tsGlob,
|
|
657
|
+
vueGlob
|
|
658
|
+
] };
|
|
659
|
+
/**
|
|
660
|
+
* Constructs the flat config items for Perfectionist linting, providing rules
|
|
661
|
+
* to naturally sort objects, imports, classes, and other elements in your code.
|
|
662
|
+
* @param options Perfectionist configuration options.
|
|
663
|
+
* @returns Promise resolving to Perfectionist ESLint config items.
|
|
664
|
+
*/
|
|
665
|
+
async function perfectionist(options) {
|
|
666
|
+
const resolved = defu(options, perfectionistDefaults);
|
|
667
|
+
const perfectionistPlugin = await importModule(import("eslint-plugin-perfectionist"));
|
|
668
|
+
const baseRules = perfectionistPlugin.configs["recommended-natural"]?.rules || {};
|
|
669
|
+
return [{
|
|
670
|
+
name: "favorodera/perfectionist/setup",
|
|
671
|
+
plugins: { perfectionist: perfectionistPlugin }
|
|
672
|
+
}, {
|
|
673
|
+
files: resolved.files,
|
|
674
|
+
name: "favorodera/perfectionist/rules",
|
|
675
|
+
rules: {
|
|
676
|
+
...baseRules,
|
|
677
|
+
"perfectionist/sort-exports": ["error", {
|
|
678
|
+
order: "asc",
|
|
679
|
+
type: "natural"
|
|
680
|
+
}],
|
|
681
|
+
"perfectionist/sort-imports": ["error", {
|
|
682
|
+
groups: [
|
|
683
|
+
"type-import",
|
|
684
|
+
[
|
|
685
|
+
"type-parent",
|
|
686
|
+
"type-sibling",
|
|
687
|
+
"type-index",
|
|
688
|
+
"type-internal"
|
|
689
|
+
],
|
|
690
|
+
"value-builtin",
|
|
691
|
+
"value-external",
|
|
692
|
+
"value-internal",
|
|
693
|
+
[
|
|
694
|
+
"value-parent",
|
|
695
|
+
"value-sibling",
|
|
696
|
+
"value-index"
|
|
697
|
+
],
|
|
698
|
+
"side-effect",
|
|
699
|
+
"ts-equals-import",
|
|
700
|
+
"unknown"
|
|
701
|
+
],
|
|
702
|
+
newlinesBetween: "ignore",
|
|
703
|
+
newlinesInside: "ignore",
|
|
704
|
+
order: "asc",
|
|
705
|
+
type: "natural"
|
|
706
|
+
}],
|
|
707
|
+
"perfectionist/sort-named-exports": ["error", {
|
|
708
|
+
order: "asc",
|
|
709
|
+
type: "natural"
|
|
710
|
+
}],
|
|
711
|
+
"perfectionist/sort-named-imports": ["error", {
|
|
712
|
+
order: "asc",
|
|
713
|
+
type: "natural"
|
|
714
|
+
}],
|
|
715
|
+
...resolved.overrides
|
|
716
|
+
}
|
|
717
|
+
}];
|
|
718
|
+
}
|
|
719
|
+
//#endregion
|
|
720
|
+
//#region src/configs/stylistic.ts
|
|
721
|
+
const stylisticDefaults = {
|
|
722
|
+
files: [
|
|
723
|
+
jsGlob,
|
|
724
|
+
tsGlob,
|
|
725
|
+
vueGlob
|
|
726
|
+
],
|
|
727
|
+
settings: {
|
|
728
|
+
experimental: false,
|
|
729
|
+
indent: 2,
|
|
730
|
+
jsx: false,
|
|
731
|
+
quotes: "single",
|
|
732
|
+
semi: false
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
/**
|
|
736
|
+
* Constructs the flat config items for Stylistic linting, applying customized
|
|
737
|
+
* formatting settings such as quotes, indentation, and spacing.
|
|
738
|
+
* @param options Stylistic configuration options.
|
|
739
|
+
* @returns Promise resolving to stylistic ESLint config items.
|
|
740
|
+
*/
|
|
741
|
+
async function stylistic(options) {
|
|
742
|
+
const resolved = defu(options, stylisticDefaults);
|
|
743
|
+
const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
|
|
744
|
+
const baseRules = stylePlugin.configs.customize({
|
|
745
|
+
pluginName: "style",
|
|
746
|
+
...resolved.settings
|
|
747
|
+
})?.rules || {};
|
|
748
|
+
return [{
|
|
749
|
+
name: "favorodera/stylistic/setup",
|
|
750
|
+
plugins: { style: stylePlugin }
|
|
751
|
+
}, {
|
|
752
|
+
files: resolved.files,
|
|
753
|
+
name: "favorodera/stylistic/rules",
|
|
754
|
+
rules: {
|
|
755
|
+
...baseRules,
|
|
756
|
+
"style/brace-style": "off",
|
|
757
|
+
"style/generator-star-spacing": ["error", {
|
|
758
|
+
after: true,
|
|
759
|
+
before: false
|
|
760
|
+
}],
|
|
761
|
+
"style/no-multiple-empty-lines": ["error", {
|
|
762
|
+
max: 2,
|
|
763
|
+
maxBOF: 0,
|
|
764
|
+
maxEOF: 2
|
|
765
|
+
}],
|
|
766
|
+
"style/no-trailing-spaces": ["error", { skipBlankLines: true }],
|
|
767
|
+
"style/padded-blocks": "off",
|
|
768
|
+
"style/quotes": [
|
|
769
|
+
"error",
|
|
770
|
+
"single",
|
|
771
|
+
{ avoidEscape: true }
|
|
772
|
+
],
|
|
773
|
+
"style/yield-star-spacing": ["error", {
|
|
774
|
+
after: true,
|
|
775
|
+
before: false
|
|
776
|
+
}],
|
|
777
|
+
...resolved.overrides
|
|
778
|
+
}
|
|
779
|
+
}];
|
|
780
|
+
}
|
|
781
|
+
//#endregion
|
|
782
|
+
//#region src/configs/tailwind.ts
|
|
783
|
+
const tailwindDefaults = {
|
|
784
|
+
files: [
|
|
785
|
+
jsGlob,
|
|
786
|
+
tsGlob,
|
|
787
|
+
vueGlob
|
|
788
|
+
],
|
|
789
|
+
settings: { detectComponentClasses: true }
|
|
790
|
+
};
|
|
791
|
+
/**
|
|
792
|
+
* Constructs the flat config items for Tailwind CSS linting, providing custom settings
|
|
793
|
+
* to parse and lint utility classes, and enforcing consistent ordering.
|
|
794
|
+
* @param options Tailwind configuration options.
|
|
795
|
+
* @returns Promise resolving to Tailwind ESLint config items.
|
|
796
|
+
*/
|
|
797
|
+
async function tailwind(options) {
|
|
798
|
+
const resolved = defu(options, tailwindDefaults);
|
|
799
|
+
const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
|
|
800
|
+
const baseRules = {
|
|
801
|
+
...tailwindPlugin.configs["recommended-error"].rules,
|
|
802
|
+
...tailwindPlugin.configs["stylistic-error"].rules
|
|
803
|
+
};
|
|
804
|
+
return [{
|
|
805
|
+
name: "favorodera/tailwind/setup",
|
|
806
|
+
plugins: { tailwind: tailwindPlugin },
|
|
807
|
+
settings: { tailwindcss: resolved.settings }
|
|
808
|
+
}, {
|
|
809
|
+
files: resolved.files,
|
|
810
|
+
name: "favorodera/tailwind/rules",
|
|
811
|
+
rules: {
|
|
812
|
+
...renamePluginsInRules(baseRules, { "better-tailwindcss": "tailwind" }),
|
|
813
|
+
"tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
|
|
814
|
+
"tailwind/no-unregistered-classes": "off",
|
|
815
|
+
...resolved.overrides
|
|
816
|
+
}
|
|
817
|
+
}];
|
|
818
|
+
}
|
|
819
|
+
//#endregion
|
|
820
|
+
//#region src/configs/typescript.ts
|
|
821
|
+
const typescriptDefaults = { files: [tsGlob] };
|
|
822
|
+
/**
|
|
823
|
+
* Constructs the flat config items for TypeScript linting, initializing the parser
|
|
824
|
+
* and extending the recommended and strict type-aware rule sets.
|
|
825
|
+
* @param options TypeScript configuration options.
|
|
826
|
+
* @returns Promise resolving to TypeScript ESLint config items.
|
|
827
|
+
*/
|
|
828
|
+
async function typescript(options) {
|
|
829
|
+
const resolved = defu(options, typescriptDefaults);
|
|
830
|
+
const tsEsLint = await importModule(import("typescript-eslint"));
|
|
831
|
+
const baseRules = extractRules(tsEsLint.configs.recommended, tsEsLint.configs.strict);
|
|
832
|
+
return [{
|
|
833
|
+
name: "favorodera/typescript/setup",
|
|
834
|
+
plugins: { ts: tsEsLint.plugin }
|
|
835
|
+
}, {
|
|
836
|
+
files: resolved.files,
|
|
837
|
+
languageOptions: {
|
|
838
|
+
parser: tsEsLint.parser,
|
|
839
|
+
parserOptions: { sourceType: "module" }
|
|
840
|
+
},
|
|
841
|
+
name: "favorodera/typescript/rules",
|
|
842
|
+
rules: {
|
|
843
|
+
...renamePluginsInRules(baseRules, { "@typescript-eslint": "ts" }),
|
|
844
|
+
"ts/array-type": ["error", {
|
|
845
|
+
default: "generic",
|
|
846
|
+
readonly: "generic"
|
|
847
|
+
}],
|
|
848
|
+
"ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
|
|
849
|
+
"ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
|
|
850
|
+
...resolved.overrides
|
|
851
|
+
}
|
|
852
|
+
}];
|
|
853
|
+
}
|
|
854
|
+
//#endregion
|
|
855
|
+
//#region src/configs/unicorn.ts
|
|
856
|
+
const unicornDefaults = { files: [
|
|
857
|
+
jsGlob,
|
|
858
|
+
tsGlob,
|
|
859
|
+
vueGlob
|
|
860
|
+
] };
|
|
861
|
+
/**
|
|
862
|
+
* Constructs the flat config items for Unicorn linting, providing a collection of
|
|
863
|
+
* awesome ESLint rules to improve code quality and enforce best practices.
|
|
864
|
+
* @param options Unicorn configuration options.
|
|
865
|
+
* @returns Promise resolving to Unicorn ESLint config items.
|
|
866
|
+
*/
|
|
867
|
+
async function unicorn(options) {
|
|
868
|
+
const resolved = defu(options, unicornDefaults);
|
|
869
|
+
const unicornPlugin = await importModule(import("eslint-plugin-unicorn"));
|
|
870
|
+
const baseRules = unicornPlugin.configs["unopinionated"]?.rules || {};
|
|
871
|
+
return [{
|
|
872
|
+
name: "favorodera/unicorn/setup",
|
|
873
|
+
plugins: { unicorn: unicornPlugin }
|
|
874
|
+
}, {
|
|
875
|
+
files: resolved.files,
|
|
876
|
+
languageOptions: { globals: globals.builtin },
|
|
877
|
+
name: "favorodera/unicorn/rules",
|
|
878
|
+
rules: {
|
|
879
|
+
...baseRules,
|
|
880
|
+
"unicorn/consistent-empty-array-spread": "error",
|
|
881
|
+
"unicorn/error-message": "error",
|
|
882
|
+
"unicorn/escape-case": "error",
|
|
883
|
+
"unicorn/new-for-builtins": "error",
|
|
884
|
+
"unicorn/no-instanceof-builtins": "error",
|
|
885
|
+
"unicorn/no-new-array": "error",
|
|
886
|
+
"unicorn/no-new-buffer": "error",
|
|
887
|
+
"unicorn/number-literal-case": "error",
|
|
888
|
+
"unicorn/prefer-dom-node-text-content": "error",
|
|
889
|
+
"unicorn/prefer-includes": "error",
|
|
890
|
+
"unicorn/prefer-node-protocol": "error",
|
|
891
|
+
"unicorn/prefer-number-properties": "error",
|
|
892
|
+
"unicorn/prefer-string-starts-ends-with": "error",
|
|
893
|
+
"unicorn/prefer-type-error": "error",
|
|
894
|
+
"unicorn/throw-new-error": "error",
|
|
895
|
+
...resolved.overrides
|
|
896
|
+
}
|
|
897
|
+
}];
|
|
898
|
+
}
|
|
899
|
+
//#endregion
|
|
900
|
+
//#region src/configs/vue.ts
|
|
901
|
+
const sfcBlocksDefaults = { blocks: {
|
|
902
|
+
customBlocks: true,
|
|
903
|
+
styles: true,
|
|
904
|
+
template: false
|
|
905
|
+
} };
|
|
906
|
+
const vueDefaults = {
|
|
907
|
+
files: [vueGlob],
|
|
908
|
+
sfcBlocks: sfcBlocksDefaults
|
|
909
|
+
};
|
|
910
|
+
/**
|
|
911
|
+
* Constructs the flat config items for Vue linting, setting up the custom template parser,
|
|
912
|
+
* Vue block processors, and rules to enforce recommended component syntax.
|
|
913
|
+
* @param options Vue configuration options.
|
|
914
|
+
* @returns Promise resolving to Vue ESLint config items.
|
|
915
|
+
*/
|
|
916
|
+
async function vue(options) {
|
|
917
|
+
const resolved = defu(options, vueDefaults);
|
|
918
|
+
const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
|
|
919
|
+
const [vuePlugin, vueParser, tsEsLint] = await Promise.all([
|
|
920
|
+
importModule(import("eslint-plugin-vue")),
|
|
921
|
+
importModule(import("vue-eslint-parser")),
|
|
922
|
+
importModule(import("typescript-eslint"))
|
|
923
|
+
]);
|
|
924
|
+
const baseRules = extractRules(vuePlugin.configs["flat/essential"], vuePlugin.configs["flat/strongly-recommended"], vuePlugin.configs["flat/recommended"]);
|
|
925
|
+
const processor = sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]);
|
|
926
|
+
return [{
|
|
927
|
+
languageOptions: { globals: {
|
|
928
|
+
computed: "readonly",
|
|
929
|
+
defineEmits: "readonly",
|
|
930
|
+
defineExpose: "readonly",
|
|
931
|
+
defineProps: "readonly",
|
|
932
|
+
onMounted: "readonly",
|
|
933
|
+
onUnmounted: "readonly",
|
|
934
|
+
reactive: "readonly",
|
|
935
|
+
ref: "readonly",
|
|
936
|
+
shallowReactive: "readonly",
|
|
937
|
+
shallowRef: "readonly",
|
|
938
|
+
toRef: "readonly",
|
|
939
|
+
toRefs: "readonly",
|
|
940
|
+
watch: "readonly",
|
|
941
|
+
watchEffect: "readonly"
|
|
942
|
+
} },
|
|
943
|
+
name: "favorodera/vue/setup",
|
|
944
|
+
plugins: { vue: vuePlugin }
|
|
945
|
+
}, {
|
|
946
|
+
files: resolved.files,
|
|
947
|
+
languageOptions: {
|
|
948
|
+
parser: vueParser,
|
|
949
|
+
parserOptions: {
|
|
950
|
+
extraFileExtensions: [".vue"],
|
|
951
|
+
parser: tsEsLint.parser,
|
|
952
|
+
sourceType: "module"
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
name: "favorodera/vue/rules",
|
|
956
|
+
processor,
|
|
957
|
+
rules: {
|
|
958
|
+
...baseRules,
|
|
959
|
+
"vue/block-order": ["error", { order: [
|
|
960
|
+
"script",
|
|
961
|
+
"template",
|
|
962
|
+
"style"
|
|
963
|
+
] }],
|
|
964
|
+
"vue/block-tag-newline": ["error", {
|
|
965
|
+
multiline: "ignore",
|
|
966
|
+
singleline: "ignore"
|
|
967
|
+
}],
|
|
968
|
+
"vue/component-name-in-template-casing": ["error", "PascalCase"],
|
|
969
|
+
"vue/component-options-name-casing": ["error", "PascalCase"],
|
|
970
|
+
"vue/multi-word-component-names": "off",
|
|
971
|
+
"vue/multiline-html-element-content-newline": ["error", {
|
|
972
|
+
allowEmptyLines: true,
|
|
973
|
+
ignores: ["pre", "textarea"]
|
|
974
|
+
}],
|
|
975
|
+
...resolved.overrides
|
|
976
|
+
}
|
|
977
|
+
}];
|
|
978
|
+
}
|
|
979
|
+
//#endregion
|
|
732
980
|
//#region src/factory.ts
|
|
733
981
|
/**
|
|
734
|
-
* Factory to create a flat ESLint config
|
|
735
|
-
*
|
|
736
|
-
* @
|
|
982
|
+
* Factory to create a flat ESLint config.
|
|
983
|
+
* It builds an ESLint config by sequentially adding sub-configs based on the provided options.
|
|
984
|
+
* @param options Configuration options for enabling/disabling or configuring specific rule sets.
|
|
985
|
+
* @returns A flat config composer instance that can be exported directly or further modified.
|
|
737
986
|
*/
|
|
738
987
|
function factory(options = {}) {
|
|
739
|
-
const configs = [];
|
|
740
|
-
configs.push(ignores(options.ignores));
|
|
988
|
+
const configs = [ignores(options.ignores)];
|
|
741
989
|
const configFunctions = {
|
|
742
|
-
vue,
|
|
743
|
-
typescript,
|
|
744
|
-
stylistic,
|
|
745
|
-
tailwind,
|
|
746
990
|
imports,
|
|
747
|
-
markdown,
|
|
748
991
|
javascript,
|
|
749
|
-
|
|
992
|
+
jsdoc,
|
|
993
|
+
jsonc,
|
|
994
|
+
markdown,
|
|
995
|
+
node,
|
|
996
|
+
perfectionist,
|
|
997
|
+
stylistic,
|
|
998
|
+
tailwind,
|
|
999
|
+
typescript,
|
|
1000
|
+
unicorn,
|
|
1001
|
+
vue
|
|
750
1002
|
};
|
|
751
1003
|
for (const [key, configFunction] of Object.entries(configFunctions)) {
|
|
752
1004
|
const configOption = options[key];
|
|
@@ -755,10 +1007,11 @@ function factory(options = {}) {
|
|
|
755
1007
|
}
|
|
756
1008
|
let composer = new FlatConfigComposer();
|
|
757
1009
|
composer = composer.append(...configs).renamePlugins({
|
|
758
|
-
"better-tailwindcss": "tailwind",
|
|
759
1010
|
"@typescript-eslint": "ts",
|
|
1011
|
+
"better-tailwindcss": "tailwind",
|
|
1012
|
+
"import-lite": "import",
|
|
760
1013
|
"markdown": "md",
|
|
761
|
-
"
|
|
1014
|
+
"n": "node"
|
|
762
1015
|
});
|
|
763
1016
|
return composer;
|
|
764
1017
|
}
|