@cuiqg/eslint-config 2.5.0 → 2.5.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.
Files changed (3) hide show
  1. package/dist/index.js +474 -349
  2. package/package.json +9 -18
  3. package/dist/index.d.ts +0 -124
package/dist/index.js CHANGED
@@ -1,29 +1,36 @@
1
1
  import { FlatConfigComposer } from "eslint-flat-config-utils";
2
- import process$1 from "node:process";
3
- import { isPackageExists } from "local-pkg";
4
2
  import globals from "globals";
3
+ import process from "node:process";
4
+ import { isPackageExists } from "local-pkg";
5
5
 
6
- //#region src/env.ts
7
- const isInGitHookOrLintStaged = () => {
8
- return !!(process$1.env.GIT_PARAMS || process$1.env.VSCODE_GIT_COMMAND || process$1.env.npm_lifecycle_script?.startsWith("lint-staged"));
9
- };
10
- const isInEditor = () => {
11
- if (process$1.env.CI) return false;
12
- if (isInGitHookOrLintStaged()) return false;
13
- return !!(process$1.env.VSCODE_PID || process$1.env.VSCODE_CWD || process$1.env.JETBRAINS_IDE || process$1.env.VIM || process$1.env.NVIM);
14
- };
15
- const hasVue = () => [
16
- "vue",
17
- "nuxt",
18
- "vitepress",
19
- "@slidev/cli"
20
- ].some((i) => isPackageExists("vue"));
21
- const hasTypeScript = () => isPackageExists("typescript");
22
- const hasUnoCss = () => isPackageExists("unocss");
23
- const hasNextjs = () => isPackageExists("next");
6
+ //#region src/utils.js
7
+ async function interopDefault(module) {
8
+ try {
9
+ let resolved = await module;
10
+ return resolved?.default || resolved;
11
+ } catch (error) {
12
+ throw new Error(`Cannot import module: ${String(error)}`);
13
+ }
14
+ }
15
+ function renameRules(rules, map) {
16
+ return Object.fromEntries(Object.entries(rules).map(([key, value]) => {
17
+ for (const [from, to] of Object.entries(map)) if (key.startsWith(`${from}/`)) return [to + key.slice(from.length), value];
18
+ return [key, value];
19
+ }));
20
+ }
24
21
 
25
22
  //#endregion
26
- //#region src/globs.ts
23
+ //#region src/configs/de-morgan.js
24
+ async function deMorgan() {
25
+ const pluginDeMorgan = await interopDefault(import("eslint-plugin-de-morgan"));
26
+ return [{
27
+ ...pluginDeMorgan.configs.recommended,
28
+ name: "cuiqg/de-morgan"
29
+ }];
30
+ }
31
+
32
+ //#endregion
33
+ //#region src/globs.js
27
34
  const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
28
35
  const GLOB_SRC = `**/*.${GLOB_SRC_EXT}`;
29
36
  const GLOB_TS = `**/*.?([cm])ts`;
@@ -93,283 +100,62 @@ const GLOB_EXCLUDE = [
93
100
  ];
94
101
 
95
102
  //#endregion
96
- //#region src/utils.ts
97
- async function interopDefault(module) {
98
- try {
99
- let resolved = await module;
100
- return resolved.default || resolved;
101
- } catch (error) {
102
- throw new Error(`Cannot import module: ${String(error)}`);
103
- }
104
- }
105
- function renameRules(rules, map) {
106
- return Object.fromEntries(Object.entries(rules).map(([key, value]) => {
107
- for (const [from, to] of Object.entries(map)) if (key.startsWith(`${from}/`)) return [to + key.slice(from.length), value];
108
- return [key, value];
109
- }));
110
- }
111
-
112
- //#endregion
113
- //#region src/configs/nextjs.ts
114
- function normalizeRules(rules) {
115
- return Object.fromEntries(Object.entries(rules).map(([key, value]) => [key, typeof value === "string" ? [value] : value]));
116
- }
117
- async function nextjs() {
118
- const files = [GLOB_SRC];
119
- const pluginNextJS = await interopDefault(import("@next/eslint-plugin-next"));
120
- return [{
121
- name: "cuiqg/nextjs/setup",
122
- plugins: { next: pluginNextJS }
123
- }, {
124
- files,
125
- languageOptions: {
126
- parserOptions: { ecmaFeatures: { jsx: true } },
127
- sourceType: "module"
128
- },
129
- name: "cuiqg/nextjs/rules",
130
- rules: {
131
- ...normalizeRules(pluginNextJS.configs.recommended.rules),
132
- ...normalizeRules(pluginNextJS.configs["core-web-vitals"].rules)
133
- },
134
- settings: { react: { version: "detect" } }
135
- }];
136
- }
137
-
138
- //#endregion
139
- //#region src/configs/node.ts
140
- async function node() {
141
- const pluginNode = await interopDefault(import("eslint-plugin-n"));
142
- return [{
143
- name: "cuiqg/node/rules",
144
- plugins: { node: pluginNode },
145
- rules: { ...pluginNode.configs.recommended.rules }
146
- }];
147
- }
148
-
149
- //#endregion
150
- //#region src/configs/package-json.ts
151
- async function packageJson() {
152
- const [pluginPackageJson, parserJson] = await Promise.all([interopDefault(import("eslint-plugin-package-json")), interopDefault(import("jsonc-eslint-parser"))]);
153
- return [{
154
- files: ["**/package.json"],
155
- plugins: { "package-json": pluginPackageJson },
156
- name: "cuiqg/package-json/setup",
157
- languageOptions: { parser: parserJson }
158
- }, {
159
- name: "cuiqg/package-json/rules",
160
- rules: { ...pluginPackageJson.configs.recommended.rules }
161
- }];
162
- }
163
-
164
- //#endregion
165
- //#region src/configs/vue.ts
166
- async function vue() {
167
- const files = [GLOB_VUE];
168
- const [pluginVue, parserVue] = await Promise.all([interopDefault(import("eslint-plugin-vue")), interopDefault(import("vue-eslint-parser"))]);
169
- return [{
170
- languageOptions: { globals: {
171
- computed: "readonly",
172
- defineEmits: "readonly",
173
- defineExpose: "readonly",
174
- defineProps: "readonly",
175
- onMounted: "readonly",
176
- onUnmounted: "readonly",
177
- reactive: "readonly",
178
- ref: "readonly",
179
- shallowReactive: "readonly",
180
- shallowRef: "readonly",
181
- toRef: "readonly",
182
- toRefs: "readonly",
183
- watch: "readonly",
184
- watchEffect: "readonly"
185
- } },
186
- name: "cuiqg/vue/setup",
187
- plugins: { vue: pluginVue }
188
- }, {
189
- files,
190
- languageOptions: {
191
- parser: parserVue,
192
- parserOptions: {
193
- ecmaFeatures: { jsx: true },
194
- extraFileExtensions: [".vue"],
195
- parser: hasTypeScript() ? await interopDefault(import("@typescript-eslint/parser")) : null,
196
- sourceType: "module"
197
- }
198
- },
199
- name: "cuiqg/vue/rules",
200
- processor: pluginVue.processors[".vue"],
201
- rules: {
202
- ...pluginVue.configs.base.rules,
203
- ...pluginVue.configs["flat/essential"].map((c) => c.rules).reduce((acc, c) => ({
204
- ...acc,
205
- ...c
206
- }), {}),
207
- ...pluginVue.configs["flat/strongly-recommended"].map((c) => c.rules).reduce((acc, c) => ({
208
- ...acc,
209
- ...c
210
- }), {}),
211
- ...pluginVue.configs["flat/recommended"].map((c) => c.rules).reduce((acc, c) => ({
212
- ...acc,
213
- ...c
214
- }), {}),
215
- "node/prefer-global/process": "off",
216
- "ts/explicit-function-return-type": "off",
217
- "vue/block-order": ["error", { order: [
218
- "script",
219
- "template",
220
- "style"
221
- ] }],
222
- "vue/component-name-in-template-casing": ["error", "PascalCase"],
223
- "vue/component-options-name-casing": ["error", "PascalCase"],
224
- "vue/component-tags-order": "off",
225
- "vue/custom-event-name-casing": ["error", "camelCase"],
226
- "vue/define-macros-order": ["error", { order: [
227
- "defineOptions",
228
- "defineProps",
229
- "defineEmits",
230
- "defineSlots"
231
- ] }],
232
- "vue/dot-location": ["error", "property"],
233
- "vue/dot-notation": ["error", { allowKeywords: true }],
234
- "vue/eqeqeq": ["error", "smart"],
235
- "vue/html-indent": ["error", 2],
236
- "vue/html-quotes": ["error", "double"],
237
- "vue/max-attributes-per-line": "off",
238
- "vue/multi-word-component-names": "off",
239
- "vue/no-dupe-keys": "off",
240
- "vue/no-empty-pattern": "error",
241
- "vue/no-irregular-whitespace": "error",
242
- "vue/no-loss-of-precision": "error",
243
- "vue/no-restricted-syntax": [
244
- "error",
245
- "DebuggerStatement",
246
- "LabeledStatement",
247
- "WithStatement"
248
- ],
249
- "vue/no-restricted-v-bind": ["error", "/^v-/"],
250
- "vue/no-setup-props-reactivity-loss": "off",
251
- "vue/no-sparse-arrays": "error",
252
- "vue/no-unused-refs": "error",
253
- "vue/no-useless-v-bind": "error",
254
- "vue/no-v-html": "off",
255
- "vue/object-shorthand": [
256
- "error",
257
- "always",
258
- {
259
- avoidQuotes: true,
260
- ignoreConstructors: false
261
- }
262
- ],
263
- "vue/prefer-separate-static-class": "error",
264
- "vue/prefer-template": "error",
265
- "vue/prop-name-casing": ["error", "camelCase"],
266
- "vue/require-default-prop": "off",
267
- "vue/require-prop-types": "off",
268
- "vue/space-infix-ops": "error",
269
- "vue/space-unary-ops": ["error", {
270
- nonwords: false,
271
- words: true
272
- }],
273
- "vue/array-bracket-spacing": ["error", "never"],
274
- "vue/arrow-spacing": ["error", {
275
- after: true,
276
- before: true
277
- }],
278
- "vue/block-spacing": ["error", "always"],
279
- "vue/block-tag-newline": ["error", {
280
- multiline: "always",
281
- singleline: "always"
282
- }],
283
- "vue/brace-style": [
284
- "error",
285
- "stroustrup",
286
- { allowSingleLine: true }
287
- ],
288
- "vue/comma-dangle": ["error", "always-multiline"],
289
- "vue/comma-spacing": ["error", {
290
- after: true,
291
- before: false
292
- }],
293
- "vue/comma-style": ["error", "last"],
294
- "vue/html-comment-content-spacing": [
295
- "error",
296
- "always",
297
- { exceptions: ["-"] }
298
- ],
299
- "vue/key-spacing": ["error", {
300
- afterColon: true,
301
- beforeColon: false
302
- }],
303
- "vue/keyword-spacing": ["error", {
304
- after: true,
305
- before: true
306
- }],
307
- "vue/object-curly-newline": "off",
308
- "vue/object-curly-spacing": ["error", "always"],
309
- "vue/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
310
- "vue/operator-linebreak": ["error", "before"],
311
- "vue/padding-line-between-blocks": ["error", "always"],
312
- "vue/quote-props": ["error", "consistent-as-needed"],
313
- "vue/space-in-parens": ["error", "never"],
314
- "vue/template-curly-spacing": "error"
315
- }
316
- }];
317
- }
318
-
319
- //#endregion
320
- //#region src/configs/ignores.ts
103
+ //#region src/configs/ignores.js
321
104
  async function ignores() {
322
105
  const configGitignore = await interopDefault(import("eslint-config-flat-gitignore"));
323
106
  return [{
324
107
  ignores: [...GLOB_EXCLUDE],
325
108
  name: "cuiqg/ignores"
326
109
  }, configGitignore({
327
- name: "cuiqg/ignores/gitignore",
110
+ name: "cuiqg/gitignore",
328
111
  strict: false
329
112
  })];
330
113
  }
331
114
 
332
115
  //#endregion
333
- //#region src/configs/unocss.ts
334
- async function unocss() {
335
- const [pluginUnoCSS] = await Promise.all([interopDefault(import("@unocss/eslint-plugin"))]);
336
- return [{
337
- name: "cuiqg/unocss",
338
- plugins: { unocss: pluginUnoCSS },
339
- rules: { ...renameRules(pluginUnoCSS.configs.recommended.rules, { "@unocss": "unocss" }) }
340
- }];
341
- }
342
-
343
- //#endregion
344
- //#region src/configs/de-morgan.ts
345
- async function deMorgan() {
346
- const pluginDeMorgan = await interopDefault(import("eslint-plugin-de-morgan"));
116
+ //#region src/configs/imports.js
117
+ async function imports() {
118
+ const pluginImportLite = await interopDefault(import("eslint-plugin-import-lite"));
347
119
  return [{
348
- ...pluginDeMorgan.configs.recommended,
349
- name: "cuiqg/de-morgan"
350
- }];
351
- }
352
-
353
- //#endregion
354
- //#region src/configs/prettier.ts
355
- async function prettier() {
356
- const [pluginPrettier, recommendedPrettier] = await Promise.all([interopDefault(import("eslint-plugin-prettier")), interopDefault(import("eslint-plugin-prettier/recommended"))]);
357
- return [{
358
- plugins: { prettier: pluginPrettier },
359
- name: "cuiqg/prettier",
120
+ name: "cuiqg/imports",
121
+ plugins: { import: pluginImportLite },
360
122
  rules: {
361
- ...recommendedPrettier.rules,
362
- "prettier/prettier": "warn"
123
+ "import/consistent-type-specifier-style": ["error", "top-level"],
124
+ "import/first": "error",
125
+ "import/newline-after-import": ["error", { count: 1 }],
126
+ "import/no-duplicates": "error",
127
+ "import/no-mutable-exports": "error",
128
+ "import/no-named-default": "error"
363
129
  }
364
130
  }];
365
131
  }
366
132
 
367
133
  //#endregion
368
- //#region src/configs/javascript.ts
134
+ //#region src/env.js
135
+ const isInGitHookOrLintStaged = () => {
136
+ return !!(process.env.GIT_PARAMS || process.env.VSCODE_GIT_COMMAND || process.env.npm_lifecycle_script?.startsWith("lint-staged"));
137
+ };
138
+ const isInEditor = () => {
139
+ if (process.env.CI) return false;
140
+ if (isInGitHookOrLintStaged()) return false;
141
+ return !!(process.env.VSCODE_PID || process.env.VSCODE_CWD || process.env.JETBRAINS_IDE || process.env.VIM || process.env.NVIM);
142
+ };
143
+ const hasVue = () => [
144
+ "vue",
145
+ "nuxt",
146
+ "vitepress",
147
+ "@slidev/cli"
148
+ ].some((i) => isPackageExists("vue"));
149
+ const hasTypeScript = () => isPackageExists("typescript");
150
+ const hasUnoCss = () => isPackageExists("unocss");
151
+ const hasNextjs = () => isPackageExists("next");
152
+
153
+ //#endregion
154
+ //#region src/configs/javascript.js
369
155
  async function javascript() {
370
156
  const [pluginUnuseImports, pluginJs] = await Promise.all([interopDefault(import("eslint-plugin-unused-imports")), interopDefault(import("@eslint/js"))]);
371
157
  return [{
372
- name: "cuiqg/javascript/setup",
158
+ name: "cuiqg/javascript",
373
159
  languageOptions: {
374
160
  ecmaVersion: "latest",
375
161
  globals: {
@@ -384,13 +170,11 @@ async function javascript() {
384
170
  },
385
171
  sourceType: "module"
386
172
  },
387
- linterOptions: { reportUnusedDisableDirectives: true }
388
- }, {
173
+ linterOptions: { reportUnusedDisableDirectives: true },
389
174
  plugins: {
390
175
  "unused-imports": pluginUnuseImports,
391
176
  js: pluginJs
392
177
  },
393
- name: "cuiqg/javascript/rules",
394
178
  rules: {
395
179
  ...pluginJs.configs.recommended.rules,
396
180
  "accessor-pairs": ["error", {
@@ -586,106 +370,447 @@ async function javascript() {
586
370
  }
587
371
 
588
372
  //#endregion
589
- //#region src/configs/typescript.ts
590
- async function typescript() {
591
- const files = [GLOB_TS, GLOB_TSX];
592
- const [pluginTs, parserTs] = await Promise.all([interopDefault(import("@typescript-eslint/eslint-plugin")), interopDefault(import("@typescript-eslint/parser"))]);
373
+ //#region src/configs/jsdoc.js
374
+ async function jsdoc() {
375
+ const pluginJsdoc = await interopDefault(import("eslint-plugin-jsdoc"));
376
+ return [{
377
+ name: "cuiqg/jsdoc",
378
+ plugins: { jsdoc: pluginJsdoc },
379
+ rules: {
380
+ "jsdoc/check-access": "warn",
381
+ "jsdoc/check-param-names": "warn",
382
+ "jsdoc/check-property-names": "warn",
383
+ "jsdoc/check-types": "warn",
384
+ "jsdoc/empty-tags": "warn",
385
+ "jsdoc/implements-on-classes": "warn",
386
+ "jsdoc/no-defaults": "warn",
387
+ "jsdoc/no-multi-asterisks": "warn",
388
+ "jsdoc/require-param-name": "warn",
389
+ "jsdoc/require-property": "warn",
390
+ "jsdoc/require-property-description": "warn",
391
+ "jsdoc/require-property-name": "warn",
392
+ "jsdoc/require-returns-check": "warn",
393
+ "jsdoc/require-returns-description": "warn",
394
+ "jsdoc/require-yields-check": "warn",
395
+ "jsdoc/check-alignment": "warn",
396
+ "jsdoc/multiline-blocks": "warn"
397
+ }
398
+ }];
399
+ }
400
+
401
+ //#endregion
402
+ //#region src/configs/jsonc.js
403
+ async function jsonc() {
404
+ const files = [
405
+ GLOB_JSON,
406
+ GLOB_JSON5,
407
+ GLOB_JSONC
408
+ ];
409
+ const [pluginJsonc, parserJsonc] = await Promise.all([interopDefault(import("eslint-plugin-jsonc")), interopDefault(import("jsonc-eslint-parser"))]);
410
+ return [{
411
+ files,
412
+ name: "cuiqg/jsonc",
413
+ plugins: { jsonc: pluginJsonc },
414
+ languageOptions: { parser: parserJsonc },
415
+ rules: {
416
+ "jsonc/no-bigint-literals": "error",
417
+ "jsonc/no-binary-expression": "error",
418
+ "jsonc/no-binary-numeric-literals": "error",
419
+ "jsonc/no-dupe-keys": "error",
420
+ "jsonc/no-escape-sequence-in-identifier": "error",
421
+ "jsonc/no-floating-decimal": "error",
422
+ "jsonc/no-hexadecimal-numeric-literals": "error",
423
+ "jsonc/no-infinity": "error",
424
+ "jsonc/no-multi-str": "error",
425
+ "jsonc/no-nan": "error",
426
+ "jsonc/no-number-props": "error",
427
+ "jsonc/no-numeric-separators": "error",
428
+ "jsonc/no-octal": "error",
429
+ "jsonc/no-octal-escape": "error",
430
+ "jsonc/no-octal-numeric-literals": "error",
431
+ "jsonc/no-parenthesized": "error",
432
+ "jsonc/no-plus-sign": "error",
433
+ "jsonc/no-regexp-literals": "error",
434
+ "jsonc/no-sparse-arrays": "error",
435
+ "jsonc/no-template-literals": "error",
436
+ "jsonc/no-undefined-value": "error",
437
+ "jsonc/no-unicode-codepoint-escapes": "error",
438
+ "jsonc/no-useless-escape": "error",
439
+ "jsonc/space-unary-ops": "error",
440
+ "jsonc/valid-json-number": "error",
441
+ "jsonc/vue-custom-block/no-parsing-error": "error",
442
+ "jsonc/array-bracket-spacing": ["error", "never"],
443
+ "jsonc/comma-dangle": ["error", "never"],
444
+ "jsonc/comma-style": ["error", "last"],
445
+ "jsonc/indent": ["error", 2],
446
+ "jsonc/key-spacing": ["error", {
447
+ afterColon: true,
448
+ beforeColon: false
449
+ }],
450
+ "jsonc/object-curly-newline": ["error", {
451
+ consistent: true,
452
+ multiline: true
453
+ }],
454
+ "jsonc/object-curly-spacing": ["error", "always"],
455
+ "jsonc/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
456
+ "jsonc/quote-props": "error",
457
+ "jsonc/quotes": "error"
458
+ }
459
+ }];
460
+ }
461
+
462
+ //#endregion
463
+ //#region src/configs/nextjs.js
464
+ function normalizeRules(rules) {
465
+ return Object.fromEntries(Object.entries(rules).map(([key, value]) => [key, typeof value === "string" ? [value] : value]));
466
+ }
467
+ async function nextjs() {
468
+ const files = [GLOB_SRC];
469
+ const pluginNextJS = await interopDefault(import("@next/eslint-plugin-next"));
593
470
  return [{
471
+ name: "cuiqg/nextjs",
594
472
  files,
595
- name: "cuiqg/typescript/setup",
596
- plugins: { ts: pluginTs },
473
+ plugins: { next: pluginNextJS },
474
+ languageOptions: {
475
+ parserOptions: { ecmaFeatures: { jsx: true } },
476
+ sourceType: "module"
477
+ },
478
+ rules: {
479
+ ...normalizeRules(pluginNextJS.configs.recommended.rules),
480
+ ...normalizeRules(pluginNextJS.configs["core-web-vitals"].rules)
481
+ },
482
+ settings: { react: { version: "detect" } }
483
+ }];
484
+ }
485
+
486
+ //#endregion
487
+ //#region src/configs/node.js
488
+ async function node() {
489
+ const pluginNode = await interopDefault(import("eslint-plugin-n"));
490
+ return [{
491
+ name: "cuiqg/node",
492
+ plugins: { node: pluginNode },
493
+ rules: {
494
+ "node/handle-callback-err": ["error", "^(err|error)$"],
495
+ "node/no-deprecated-api": "error",
496
+ "node/no-exports-assign": "error",
497
+ "node/no-new-require": "error",
498
+ "node/no-path-concat": "error",
499
+ "node/prefer-global/buffer": ["error", "never"],
500
+ "node/prefer-global/process": ["error", "never"],
501
+ "node/process-exit-as-throw": "error"
502
+ }
503
+ }];
504
+ }
505
+
506
+ //#endregion
507
+ //#region src/configs/package-json.js
508
+ async function packageJson() {
509
+ const [pluginPackageJson, pluginDepend, parserJsonc] = await Promise.all([
510
+ interopDefault(import("eslint-plugin-package-json")),
511
+ interopDefault(import("eslint-plugin-depend")),
512
+ interopDefault(import("jsonc-eslint-parser"))
513
+ ]);
514
+ return [{
515
+ files: ["**/package.json"],
516
+ plugins: {
517
+ depend: pluginDepend,
518
+ "package-json": pluginPackageJson
519
+ },
520
+ languageOptions: { parser: parserJsonc },
521
+ name: "cuiqg/package-json",
522
+ rules: {
523
+ "depend/ban-dependencies": "error",
524
+ ...pluginPackageJson.configs.recommended.rules
525
+ },
526
+ settings: { packageJson: { enforceForPrivate: false } }
527
+ }];
528
+ }
529
+
530
+ //#endregion
531
+ //#region src/configs/perfectionist.js
532
+ async function perfectionist() {
533
+ const pluginPerfectionist = await interopDefault(import("eslint-plugin-perfectionist"));
534
+ return [{
535
+ name: "cuiqg/perfectionist",
536
+ plugins: { perfectionist: pluginPerfectionist },
537
+ rules: {
538
+ "perfectionist/sort-exports": ["error", {
539
+ order: "asc",
540
+ type: "natural"
541
+ }],
542
+ "perfectionist/sort-imports": ["error", {
543
+ groups: [
544
+ "type",
545
+ [
546
+ "parent-type",
547
+ "sibling-type",
548
+ "index-type",
549
+ "internal-type"
550
+ ],
551
+ "builtin",
552
+ "external",
553
+ "internal",
554
+ [
555
+ "parent",
556
+ "sibling",
557
+ "index"
558
+ ],
559
+ "side-effect",
560
+ "object",
561
+ "unknown"
562
+ ],
563
+ newlinesBetween: "ignore",
564
+ order: "asc",
565
+ type: "natural"
566
+ }],
567
+ "perfectionist/sort-named-exports": ["error", {
568
+ order: "asc",
569
+ type: "natural"
570
+ }],
571
+ "perfectionist/sort-named-imports": ["error", {
572
+ order: "asc",
573
+ type: "natural"
574
+ }]
575
+ },
576
+ settings: { perfectionist: {
577
+ order: "desc",
578
+ type: "line-length"
579
+ } }
580
+ }];
581
+ }
582
+
583
+ //#endregion
584
+ //#region src/configs/prettier.js
585
+ async function prettier() {
586
+ const [pluginPrettier, recommendedPrettier] = await Promise.all([interopDefault(import("eslint-plugin-prettier")), interopDefault(import("eslint-plugin-prettier/recommended"))]);
587
+ return [{
588
+ plugins: { prettier: pluginPrettier },
589
+ name: "cuiqg/prettier",
590
+ rules: {
591
+ ...recommendedPrettier.rules,
592
+ "prettier/prettier": "warn"
593
+ }
594
+ }];
595
+ }
596
+
597
+ //#endregion
598
+ //#region src/configs/stylistic.js
599
+ async function stylistic() {
600
+ const pluginStylistic = await interopDefault(import("@stylistic/eslint-plugin"));
601
+ const config = pluginStylistic.configs.customize({
602
+ pluginName: "style",
603
+ indent: 2,
604
+ quotes: "single",
605
+ semi: false
606
+ });
607
+ return [{
608
+ name: "cuiqg/stylistic",
609
+ plugins: { style: pluginStylistic },
610
+ rules: {
611
+ ...config.rules,
612
+ "style/generator-star-spacing": ["error", {
613
+ after: true,
614
+ before: false
615
+ }],
616
+ "style/yield-star-spacing": ["error", {
617
+ after: true,
618
+ before: false
619
+ }]
620
+ }
621
+ }];
622
+ }
623
+
624
+ //#endregion
625
+ //#region src/configs/unocss.js
626
+ async function unocss() {
627
+ const [pluginUnoCSS] = await Promise.all([interopDefault(import("@unocss/eslint-plugin"))]);
628
+ return [{
629
+ name: "cuiqg/unocss",
630
+ plugins: { unocss: pluginUnoCSS },
631
+ rules: { ...renameRules(pluginUnoCSS.configs.recommended.rules, { "@unocss": "unocss" }) }
632
+ }];
633
+ }
634
+
635
+ //#endregion
636
+ //#region src/configs/vue.js
637
+ async function vue() {
638
+ const files = [GLOB_VUE];
639
+ const [pluginVue, parserVue] = await Promise.all([interopDefault(import("eslint-plugin-vue")), interopDefault(import("vue-eslint-parser"))]);
640
+ return [{
597
641
  languageOptions: {
598
- parser: parserTs,
642
+ globals: {
643
+ computed: "readonly",
644
+ defineEmits: "readonly",
645
+ defineExpose: "readonly",
646
+ defineProps: "readonly",
647
+ onMounted: "readonly",
648
+ onUnmounted: "readonly",
649
+ reactive: "readonly",
650
+ ref: "readonly",
651
+ shallowReactive: "readonly",
652
+ shallowRef: "readonly",
653
+ toRef: "readonly",
654
+ toRefs: "readonly",
655
+ watch: "readonly",
656
+ watchEffect: "readonly"
657
+ },
658
+ parser: parserVue,
599
659
  parserOptions: {
600
660
  ecmaFeatures: { jsx: true },
601
- ecmaVersion: "latest",
602
- projectService: true,
603
- sourceType: "module",
604
- tsconfigRootDir: process.cwd()
661
+ extraFileExtensions: [".vue"],
662
+ parser: null,
663
+ sourceType: "module"
605
664
  }
606
- }
607
- }, {
608
- name: "cuiqg/typescript/rules",
665
+ },
666
+ name: "cuiqg/vue",
667
+ plugins: { vue: pluginVue },
668
+ files,
669
+ processor: pluginVue.processors[".vue"],
609
670
  rules: {
610
- ...renameRules(pluginTs.configs["eslint-recommended"].overrides[0].rules, { "@typescript-eslint": "ts" }),
611
- ...renameRules(pluginTs.configs.strict.rules, { "@typescript-eslint": "ts" }),
612
- "no-dupe-class-members": "off",
613
- "no-redeclare": "off",
614
- "no-use-before-define": "off",
615
- "no-useless-constructor": "off",
616
- "ts/ban-ts-comment": ["error", { "ts-expect-error": "allow-with-description" }],
617
- "ts/consistent-type-definitions": ["error", "interface"],
618
- "ts/consistent-type-imports": ["error", {
619
- disallowTypeAnnotations: false,
620
- fixStyle: "separate-type-imports",
621
- prefer: "type-imports"
671
+ ...pluginVue.configs.base.rules,
672
+ ...pluginVue.configs["flat/essential"].map((c) => c.rules).reduce((acc, c) => ({
673
+ ...acc,
674
+ ...c
675
+ }), {}),
676
+ ...pluginVue.configs["flat/strongly-recommended"].map((c) => c.rules).reduce((acc, c) => ({
677
+ ...acc,
678
+ ...c
679
+ }), {}),
680
+ ...pluginVue.configs["flat/recommended"].map((c) => c.rules).reduce((acc, c) => ({
681
+ ...acc,
682
+ ...c
683
+ }), {}),
684
+ "node/prefer-global/process": "off",
685
+ "vue/block-order": ["error", { order: [
686
+ "script",
687
+ "template",
688
+ "style"
689
+ ] }],
690
+ "vue/component-name-in-template-casing": ["error", "PascalCase"],
691
+ "vue/component-options-name-casing": ["error", "PascalCase"],
692
+ "vue/component-tags-order": "off",
693
+ "vue/custom-event-name-casing": ["error", "camelCase"],
694
+ "vue/define-macros-order": ["error", { order: [
695
+ "defineOptions",
696
+ "defineProps",
697
+ "defineEmits",
698
+ "defineSlots"
699
+ ] }],
700
+ "vue/dot-location": ["error", "property"],
701
+ "vue/dot-notation": ["error", { allowKeywords: true }],
702
+ "vue/eqeqeq": ["error", "smart"],
703
+ "vue/html-indent": ["error", 2],
704
+ "vue/html-quotes": ["error", "double"],
705
+ "vue/max-attributes-per-line": "off",
706
+ "vue/multi-word-component-names": "off",
707
+ "vue/no-dupe-keys": "off",
708
+ "vue/no-empty-pattern": "error",
709
+ "vue/no-irregular-whitespace": "error",
710
+ "vue/no-loss-of-precision": "error",
711
+ "vue/no-restricted-syntax": [
712
+ "error",
713
+ "DebuggerStatement",
714
+ "LabeledStatement",
715
+ "WithStatement"
716
+ ],
717
+ "vue/no-restricted-v-bind": ["error", "/^v-/"],
718
+ "vue/no-setup-props-reactivity-loss": "off",
719
+ "vue/no-sparse-arrays": "error",
720
+ "vue/no-unused-refs": "error",
721
+ "vue/no-useless-v-bind": "error",
722
+ "vue/no-v-html": "off",
723
+ "vue/object-shorthand": [
724
+ "error",
725
+ "always",
726
+ {
727
+ avoidQuotes: true,
728
+ ignoreConstructors: false
729
+ }
730
+ ],
731
+ "vue/prefer-separate-static-class": "error",
732
+ "vue/prefer-template": "error",
733
+ "vue/prop-name-casing": ["error", "camelCase"],
734
+ "vue/require-default-prop": "off",
735
+ "vue/require-prop-types": "off",
736
+ "vue/space-infix-ops": "error",
737
+ "vue/space-unary-ops": ["error", {
738
+ nonwords: false,
739
+ words: true
622
740
  }],
623
- "ts/method-signature-style": ["error", "property"],
624
- "ts/no-dupe-class-members": "error",
625
- "ts/no-dynamic-delete": "off",
626
- "ts/no-empty-object-type": ["error", { allowInterfaces: "always" }],
627
- "ts/no-explicit-any": "off",
628
- "ts/no-extraneous-class": "off",
629
- "ts/no-import-type-side-effects": "error",
630
- "ts/no-invalid-void-type": "off",
631
- "ts/no-non-null-assertion": "off",
632
- "ts/no-redeclare": ["error", { builtinGlobals: false }],
633
- "ts/no-require-imports": "error",
634
- "ts/no-unused-expressions": ["error", {
635
- allowShortCircuit: true,
636
- allowTaggedTemplates: true,
637
- allowTernary: true
741
+ "vue/array-bracket-spacing": ["error", "never"],
742
+ "vue/arrow-spacing": ["error", {
743
+ after: true,
744
+ before: true
638
745
  }],
639
- "ts/no-unused-vars": "off",
640
- "ts/no-use-before-define": ["error", {
641
- classes: false,
642
- functions: false,
643
- variables: true
746
+ "vue/block-spacing": ["error", "always"],
747
+ "vue/block-tag-newline": ["error", {
748
+ multiline: "always",
749
+ singleline: "always"
750
+ }],
751
+ "vue/brace-style": [
752
+ "error",
753
+ "stroustrup",
754
+ { allowSingleLine: true }
755
+ ],
756
+ "vue/comma-dangle": ["error", "always-multiline"],
757
+ "vue/comma-spacing": ["error", {
758
+ after: true,
759
+ before: false
644
760
  }],
645
- "ts/no-useless-constructor": "off",
646
- "ts/no-wrapper-object-types": "error",
647
- "ts/triple-slash-reference": "off",
648
- "ts/unified-signatures": "off"
761
+ "vue/comma-style": ["error", "last"],
762
+ "vue/html-comment-content-spacing": [
763
+ "error",
764
+ "always",
765
+ { exceptions: ["-"] }
766
+ ],
767
+ "vue/key-spacing": ["error", {
768
+ afterColon: true,
769
+ beforeColon: false
770
+ }],
771
+ "vue/keyword-spacing": ["error", {
772
+ after: true,
773
+ before: true
774
+ }],
775
+ "vue/object-curly-newline": "off",
776
+ "vue/object-curly-spacing": ["error", "always"],
777
+ "vue/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
778
+ "vue/operator-linebreak": ["error", "before"],
779
+ "vue/padding-line-between-blocks": ["error", "always"],
780
+ "vue/quote-props": ["error", "consistent-as-needed"],
781
+ "vue/space-in-parens": ["error", "never"],
782
+ "vue/template-curly-spacing": "error"
649
783
  }
650
784
  }];
651
785
  }
652
786
 
653
787
  //#endregion
654
- //#region src/presets.ts
788
+ //#region src/presets.js
655
789
  const defaultPluginRenaming = {
656
790
  "@next/next": "next",
657
791
  n: "node",
658
792
  vitest: "test",
659
- yml: "yaml",
660
- "@typescript-eslint": "ts"
793
+ "import-lite": "import",
794
+ "@stylistic": "style"
661
795
  };
662
796
  function cuiqg(options = {}, ...userConfigs) {
663
- const { prettier: enablePrettier = false, typescript: enableTypeScript = hasTypeScript(), vue: enableVue = hasVue(), unocss: enableUnocss = hasUnoCss(), nextjs: enableNextjs = hasNextjs() } = options;
664
- const configs = [
665
- packageJson(),
666
- ignores(),
667
- node(),
668
- deMorgan(),
669
- javascript()
670
- ];
671
- if (enableTypeScript) configs.push(typescript());
797
+ const { prettier: enablePrettier = false, imports: enableImports = true, vue: enableVue = hasVue(), unocss: enableUnocss = hasUnoCss(), nextjs: enableNextjs = hasNextjs() } = options;
798
+ const configs = [];
799
+ configs.push(deMorgan(), ignores(), javascript(), jsdoc(), jsonc(), stylistic(), perfectionist());
800
+ if (enableImports) configs.push(imports());
672
801
  if (enableVue) configs.push(vue());
673
802
  if (enableUnocss) configs.push(unocss());
674
803
  if (enableNextjs) configs.push(nextjs());
675
804
  if (enablePrettier) configs.push(prettier());
676
805
  let composer = new FlatConfigComposer();
677
806
  composer = composer.append(...configs, ...userConfigs).renamePlugins(defaultPluginRenaming);
678
- if (isInEditor()) composer = composer.disableRulesFix([
679
- "unused-imports/no-unused-imports",
680
- "test/no-only-tests",
681
- "prefer-const"
682
- ], { builtinRules: () => import(["eslint", "use-at-your-own-risk"].join("/")).then((r) => r.builtinRules) });
807
+ if (isInEditor()) composer = composer.disableRulesFix(["unused-imports/no-unused-imports", "prefer-const"], { builtinRules: () => import(["eslint", "use-at-your-own-risk"].join("/")).then((r) => r.builtinRules) });
683
808
  return composer;
684
809
  }
685
810
 
686
811
  //#endregion
687
- //#region src/index.ts
812
+ //#region src/index.js
688
813
  var src_default = cuiqg;
689
814
 
690
815
  //#endregion
691
- export { GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_STYLUS, GLOB_SVG, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, cuiqg, deMorgan, src_default as default, defaultPluginRenaming, hasNextjs, hasTypeScript, hasUnoCss, hasVue, ignores, isInEditor, isInGitHookOrLintStaged, javascript, nextjs, node, packageJson, prettier, typescript, unocss, vue };
816
+ export { GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_STYLUS, GLOB_SVG, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, cuiqg, deMorgan, src_default as default, defaultPluginRenaming, hasNextjs, hasTypeScript, hasUnoCss, hasVue, ignores, imports, isInEditor, isInGitHookOrLintStaged, javascript, jsdoc, jsonc, nextjs, node, packageJson, perfectionist, prettier, stylistic, unocss, vue };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cuiqg/eslint-config",
3
- "version": "2.5.0",
3
+ "version": "2.5.2",
4
4
  "description": "Eslint config for @cuiqg",
5
5
  "keywords": [
6
6
  "eslint-config"
@@ -16,17 +16,13 @@
16
16
  "type": "module",
17
17
  "devDependencies": {
18
18
  "@cuiqg/prettier-config": "latest",
19
- "@cuiqg/typescript-config": "^0.1.2",
20
19
  "@eslint/config-inspector": "^1.1.0",
21
20
  "@eslint/eslintrc": "^3.3.1",
22
- "@types/node": "^24.2.0",
23
- "@vitest/ui": "^3.2.4",
24
21
  "bumpp": "^10.2.2",
25
22
  "eslint": "^9.32.0",
26
23
  "prettier": "^3.6.2",
27
24
  "publint": "^0.3.12",
28
- "tsdown": "^0.13.3",
29
- "vitest": "^3.2.4"
25
+ "tsdown": "^0.13.3"
30
26
  },
31
27
  "peerDependencies": {
32
28
  "eslint": ">=9.28.0"
@@ -34,24 +30,22 @@
34
30
  "dependencies": {
35
31
  "@eslint/js": "^9.32.0",
36
32
  "@next/eslint-plugin-next": "^15.4.6",
37
- "@typescript-eslint/eslint-plugin": "^8.39.0",
38
- "@typescript-eslint/parser": "^8.39.0",
33
+ "@stylistic/eslint-plugin": "^5.2.3",
39
34
  "@unocss/eslint-plugin": "^66.4.2",
40
35
  "eslint-config-flat-gitignore": "^2.1.0",
41
36
  "eslint-config-prettier": "^10.1.8",
42
37
  "eslint-flat-config-utils": "^2.1.1",
43
- "eslint-merge-processors": "^2.0.0",
44
38
  "eslint-plugin-de-morgan": "^1.3.1",
45
39
  "eslint-plugin-depend": "^1.2.0",
46
- "eslint-plugin-import-x": "^4.16.1",
40
+ "eslint-plugin-import-lite": "^0.3.0",
47
41
  "eslint-plugin-jsdoc": "^52.0.4",
42
+ "eslint-plugin-jsonc": "^2.20.1",
48
43
  "eslint-plugin-n": "^17.21.3",
49
44
  "eslint-plugin-package-json": "^0.52.1",
45
+ "eslint-plugin-perfectionist": "^4.15.0",
50
46
  "eslint-plugin-prettier": "^5.5.4",
51
47
  "eslint-plugin-unused-imports": "^4.1.4",
52
48
  "eslint-plugin-vue": "^10.4.0",
53
- "eslint-plugin-vuejs-accessibility": "^2.4.1",
54
- "eslint-processor-vue-blocks": "^2.0.0",
55
49
  "globals": "^16.3.0",
56
50
  "jsonc-eslint-parser": "^2.4.0",
57
51
  "local-pkg": "^1.1.1",
@@ -62,18 +56,15 @@
62
56
  "exports": {
63
57
  ".": "./dist/index.js"
64
58
  },
65
- "types": "./dist/index.d.ts",
66
59
  "files": [
67
60
  "./dist"
68
61
  ],
69
62
  "scripts": {
70
63
  "build": "tsdown",
71
64
  "dev": "tsdown --watch",
72
- "build:inspect": "pnpm build && eslint-config-inspector build --config eslint-inspector.config.ts",
65
+ "build:inspect": "eslint-config-inspector build --config eslint-inspector.config.js",
73
66
  "lint": "eslint .",
74
- "lint:inspect": "eslint-config-inspector --open false --config eslint-inspector.config.ts",
75
- "release": "bumpp && pnpm publish",
76
- "test": "vitest --ui",
77
- "typecheck": "tsc --noEmit --pretty"
67
+ "lint:inspect": "eslint-config-inspector --open false --config eslint-inspector.config.js",
68
+ "release": "bumpp && pnpm publish"
78
69
  }
79
70
  }
package/dist/index.d.ts DELETED
@@ -1,124 +0,0 @@
1
- import { FlatConfigComposer } from "eslint-flat-config-utils";
2
- import { Linter } from "eslint";
3
-
4
- //#region src/types.d.ts
5
- type Awaitable<T> = T | Promise<T>;
6
- type FlatConfigItem = Omit<Linter.Config, 'plugins'> & {
7
- plugins?: Record<string, any>;
8
- };
9
- interface OptionsOverrides {
10
- overrides?: Linter.Config['rules'];
11
- }
12
- interface OptionsFiles {
13
- files?: Array<string | string[]>;
14
- }
15
- interface OptionsConfig {
16
- /**
17
- * @default true
18
- */
19
- gitignore?: boolean;
20
- /**
21
- * @default true
22
- */
23
- javascript?: boolean;
24
- /**
25
- * @default hasTypeScript()
26
- */
27
- typescript?: boolean;
28
- /**
29
- * @default true
30
- */
31
- imports?: boolean;
32
- /**
33
- * @default hasVue()
34
- */
35
- vue?: boolean;
36
- /**
37
- * @default false
38
- */
39
- prettier?: boolean;
40
- /**
41
- * @default hasUnoCss()
42
- */
43
- unocss?: boolean;
44
- /**
45
- * @default false
46
- */
47
- nextjs?: boolean;
48
- }
49
- //#endregion
50
- //#region src/presets.d.ts
51
- declare const defaultPluginRenaming: {
52
- '@next/next': string;
53
- n: string;
54
- vitest: string;
55
- yml: string;
56
- '@typescript-eslint': string;
57
- };
58
- declare function cuiqg(options?: OptionsConfig & Omit<FlatConfigItem, 'files'>, ...userConfigs: Awaitable<FlatConfigItem | FlatConfigItem[]>[]): FlatConfigComposer<FlatConfigItem, string>;
59
- //#endregion
60
- //#region src/configs/nextjs.d.ts
61
- declare function nextjs(): Promise<FlatConfigItem[]>;
62
- //#endregion
63
- //#region src/configs/node.d.ts
64
- declare function node(): Promise<FlatConfigItem[]>;
65
- //#endregion
66
- //#region src/configs/package-json.d.ts
67
- declare function packageJson(): Promise<FlatConfigItem[]>;
68
- //#endregion
69
- //#region src/configs/vue.d.ts
70
- declare function vue(): Promise<FlatConfigItem[]>;
71
- //#endregion
72
- //#region src/configs/ignores.d.ts
73
- declare function ignores(): Promise<FlatConfigItem[]>;
74
- //#endregion
75
- //#region src/configs/unocss.d.ts
76
- declare function unocss(): Promise<FlatConfigItem[]>;
77
- //#endregion
78
- //#region src/configs/de-morgan.d.ts
79
- declare function deMorgan(): Promise<FlatConfigItem[]>;
80
- //#endregion
81
- //#region src/configs/prettier.d.ts
82
- declare function prettier(): Promise<FlatConfigItem[]>;
83
- //#endregion
84
- //#region src/configs/javascript.d.ts
85
- declare function javascript(): Promise<FlatConfigItem[]>;
86
- //#endregion
87
- //#region src/configs/typescript.d.ts
88
- declare function typescript(): Promise<FlatConfigItem[]>;
89
- //#endregion
90
- //#region src/env.d.ts
91
- declare const isInGitHookOrLintStaged: () => boolean;
92
- declare const isInEditor: () => boolean;
93
- declare const hasVue: () => boolean;
94
- declare const hasTypeScript: () => boolean;
95
- declare const hasUnoCss: () => boolean;
96
- declare const hasNextjs: () => boolean;
97
- //#endregion
98
- //#region src/globs.d.ts
99
- declare const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
100
- declare const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
101
- declare const GLOB_TS = "**/*.?([cm])ts";
102
- declare const GLOB_TSX = "**/*.?([cm])tsx";
103
- declare const GLOB_JS = "**/*.?([cm])js";
104
- declare const GLOB_JSX = "**/*.?([cm])jsx";
105
- declare const GLOB_STYLE = "**/*.{c,le,sc}ss";
106
- declare const GLOB_CSS = "**/*.css";
107
- declare const GLOB_SCSS = "**/*.scss";
108
- declare const GLOB_LESS = "**/*.less";
109
- declare const GLOB_STYLUS = "**/*.styl";
110
- declare const GLOB_POSTCSS = "**/*.{p,post}css";
111
- declare const GLOB_JSON = "**/*.json";
112
- declare const GLOB_JSON5 = "**/*.json5";
113
- declare const GLOB_JSONC = "**/*.jsonc";
114
- declare const GLOB_MARKDOWN = "**/*.md";
115
- declare const GLOB_VUE = "**/*.vue";
116
- declare const GLOB_YAML = "**/*.y?(a)ml";
117
- declare const GLOB_TOML = "**/*.toml";
118
- declare const GLOB_XML = "**/*.xml";
119
- declare const GLOB_SVG = "**/*.svg";
120
- declare const GLOB_HTML = "**/*.htm?(l)";
121
- declare const GLOB_ALL_SRC: string[];
122
- declare const GLOB_EXCLUDE: string[];
123
- //#endregion
124
- export { Awaitable, FlatConfigItem, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_STYLUS, GLOB_SVG, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, OptionsConfig, OptionsFiles, OptionsOverrides, cuiqg, deMorgan, cuiqg as default, defaultPluginRenaming, hasNextjs, hasTypeScript, hasUnoCss, hasVue, ignores, isInEditor, isInGitHookOrLintStaged, javascript, nextjs, node, packageJson, prettier, typescript, unocss, vue };