@agilebot/eslint-config 0.6.0 → 0.7.0-beta.1

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs ADDED
@@ -0,0 +1,1093 @@
1
+ /**
2
+ * @license @agilebot/eslint-config v0.7.0-beta.1
3
+ *
4
+ * Copyright (c) Agilebot, Inc. and its affiliates.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ import {
11
+ DEFAULT_GLOBS,
12
+ DTS_GLOBS,
13
+ IGNORE_GLOBS,
14
+ JS_GLOBS,
15
+ TS_GLOBS,
16
+ VUE_GLOBS,
17
+ __dirname,
18
+ define_STANDARD_RULES_default
19
+ } from "./chunk-XQZGZMJY.mjs";
20
+
21
+ // src/factory/index.ts
22
+ import assert from "node:assert";
23
+ import { findTsconfigFiles } from "@agilebot/eslint-utils";
24
+ import * as parserTs from "@typescript-eslint/parser";
25
+ import * as parserVue from "vue-eslint-parser";
26
+
27
+ // src/configs/env.ts
28
+ import globals from "globals";
29
+ function env() {
30
+ return {
31
+ name: "agilebot/env",
32
+ files: DEFAULT_GLOBS,
33
+ languageOptions: {
34
+ globals: {
35
+ ...globals.browser,
36
+ ...globals.node,
37
+ ...globals.es2015,
38
+ ...globals.mocha,
39
+ ...globals.jest,
40
+ ...globals.jasmine
41
+ }
42
+ }
43
+ };
44
+ }
45
+
46
+ // src/configs/standard.ts
47
+ import pluginImport from "eslint-plugin-import-x";
48
+ import pluginNode from "eslint-plugin-n";
49
+ import pluginPromise from "eslint-plugin-promise";
50
+ import pluginTs from "@typescript-eslint/eslint-plugin";
51
+ function standard() {
52
+ const standardRules = {};
53
+ const originalStdRules = (
54
+ // @ts-expect-error -- extracted rules from eslint-config-love
55
+ typeof define_STANDARD_RULES_default === "undefined" ? {} : (
56
+ // @ts-expect-error -- extracted rules from eslint-config-love
57
+ define_STANDARD_RULES_default
58
+ )
59
+ );
60
+ const disabledRules = new Set(Object.values(standardDisabled()).flat());
61
+ Object.entries(originalStdRules).forEach(([key, value]) => {
62
+ if (disabledRules.has(key)) {
63
+ return;
64
+ }
65
+ if (key.startsWith("import/")) {
66
+ standardRules[`import-x/${key.slice(7)}`] = value;
67
+ } else {
68
+ standardRules[key] = value;
69
+ }
70
+ });
71
+ return {
72
+ name: "agilebot/standard",
73
+ files: DEFAULT_GLOBS,
74
+ plugins: {
75
+ n: pluginNode,
76
+ "@typescript-eslint": pluginTs,
77
+ promise: pluginPromise,
78
+ "import-x": pluginImport
79
+ },
80
+ rules: {
81
+ ...standardRules,
82
+ "no-alert": "error",
83
+ // 找出TODO注释,以便后期修复
84
+ "no-warning-comments": [
85
+ "warn",
86
+ {
87
+ terms: ["todo", "fixme"]
88
+ }
89
+ ],
90
+ // 避免使用同步方法
91
+ "n/no-sync": "error",
92
+ // 尽量使用fs.promises而不是fs
93
+ "n/prefer-promises/fs": "error",
94
+ "n/prefer-promises/dns": "error",
95
+ // 路径拼接使用path.join,而不是直接使用加号
96
+ "n/no-path-concat": "error",
97
+ "promise/no-return-wrap": "error",
98
+ "promise/no-nesting": "error",
99
+ "promise/no-promise-in-callback": "error",
100
+ "promise/no-callback-in-promise": "error",
101
+ "promise/param-names": "error",
102
+ "promise/valid-params": "error",
103
+ "promise/no-multiple-resolved": "error",
104
+ "promise/no-return-in-finally": "error",
105
+ "promise/prefer-await-to-then": "warn",
106
+ // 自定义standard规则
107
+ "@typescript-eslint/max-params": ["error", { max: 5 }],
108
+ "@typescript-eslint/only-throw-error": [
109
+ "error",
110
+ {
111
+ allowThrowingAny: true,
112
+ allowThrowingUnknown: true
113
+ }
114
+ ],
115
+ "@typescript-eslint/no-loop-func": "warn"
116
+ }
117
+ };
118
+ }
119
+ function standardDisabled() {
120
+ return {
121
+ uncategoized: [
122
+ "@typescript-eslint/no-extraneous-class",
123
+ "@typescript-eslint/consistent-type-assertions",
124
+ "@typescript-eslint/no-non-null-assertion"
125
+ ],
126
+ "v9.0.0": ["@typescript-eslint/strict-boolean-expressions"],
127
+ "v10.0.0": ["@typescript-eslint/explicit-function-return-type"],
128
+ "v12.0.0": [
129
+ "@typescript-eslint/restrict-template-expressions",
130
+ "@typescript-eslint/space-before-function-paren"
131
+ ],
132
+ "v17.0.0": [
133
+ "@typescript-eslint/no-invalid-void-type",
134
+ "@typescript-eslint/method-signature-style"
135
+ ],
136
+ "v26.0.0": ["@typescript-eslint/no-confusing-void-expression"],
137
+ "v40.0.0": ["@typescript-eslint/unbound-method"],
138
+ "v42.0.0": ["@typescript-eslint/no-unsafe-argument"],
139
+ "v55.0.0": ["@typescript-eslint/class-methods-use-this"],
140
+ "v57.0.0": [
141
+ "@typescript-eslint/init-declarations",
142
+ "@typescript-eslint/no-empty-function"
143
+ ],
144
+ "v58.0.0": ["@typescript-eslint/no-explicit-any"],
145
+ "v64.0.0": ["@typescript-eslint/no-deprecated"],
146
+ "v65.0.0": ["@typescript-eslint/no-magic-numbers"],
147
+ "v70.0.0": ["@typescript-eslint/no-unnecessary-condition"],
148
+ "v75.0.0": ["@typescript-eslint/no-unnecessary-type-parameters"],
149
+ "v76.0.0": ["@typescript-eslint/no-unsafe-assignment"],
150
+ "v77.0.0": ["@typescript-eslint/no-unsafe-call"],
151
+ "v79.0.0": ["@typescript-eslint/no-unsafe-enum-comparison"],
152
+ "v80.0.0": ["@typescript-eslint/no-unsafe-member-access"],
153
+ "v81.0.0": ["@typescript-eslint/no-unsafe-return"],
154
+ "v82.0.0": ["@typescript-eslint/no-unsafe-unary-minus"],
155
+ "v89.0.0": ["@typescript-eslint/prefer-destructuring"]
156
+ };
157
+ }
158
+
159
+ // src/configs/ts.ts
160
+ import { isInEditor } from "@agilebot/eslint-utils";
161
+ import * as pluginTs2 from "@typescript-eslint/eslint-plugin";
162
+ import pluginStylistic from "@stylistic/eslint-plugin";
163
+ import pluginPreferArrowFunctions from "eslint-plugin-prefer-arrow-functions";
164
+ import pluginUnusedImports from "eslint-plugin-unused-imports";
165
+ function ts() {
166
+ return {
167
+ name: "agilebot/ts",
168
+ files: DEFAULT_GLOBS,
169
+ plugins: {
170
+ "@typescript-eslint": pluginTs2,
171
+ "@stylistic": pluginStylistic,
172
+ "prefer-arrow-functions": pluginPreferArrowFunctions,
173
+ "unused-imports": pluginUnusedImports
174
+ },
175
+ rules: {
176
+ // 如果没用模板字符串,避免使用反引号
177
+ "@stylistic/quotes": ["error", "single", { avoidEscape: true }],
178
+ "prefer-arrow-functions/prefer-arrow-functions": [
179
+ "warn",
180
+ {
181
+ allowNamedFunctions: true,
182
+ classPropertiesAllowed: false,
183
+ disallowPrototype: false,
184
+ returnStyle: "unchanged",
185
+ singleReturnOnly: false
186
+ }
187
+ ],
188
+ "@typescript-eslint/no-unused-vars": "off",
189
+ "unused-imports/no-unused-imports": isInEditor() ? "off" : "error",
190
+ "unused-imports/no-unused-vars": [
191
+ "warn",
192
+ {
193
+ args: "after-used",
194
+ argsIgnorePattern: "^_",
195
+ vars: "all",
196
+ varsIgnorePattern: "^_",
197
+ caughtErrors: "none",
198
+ caughtErrorsIgnorePattern: "^_",
199
+ destructuredArrayIgnorePattern: "^_",
200
+ ignoreRestSiblings: true
201
+ }
202
+ ],
203
+ // 优先使用interface而不是type
204
+ "@typescript-eslint/consistent-type-definitions": "error",
205
+ "@typescript-eslint/naming-convention": [
206
+ "error",
207
+ // variable规则在@agilebot/var-naming中定义
208
+ {
209
+ selector: "function",
210
+ format: ["camelCase", "PascalCase"]
211
+ },
212
+ {
213
+ selector: "variable",
214
+ types: ["function"],
215
+ format: ["camelCase", "PascalCase"]
216
+ },
217
+ {
218
+ selector: "typeLike",
219
+ format: ["PascalCase"]
220
+ },
221
+ {
222
+ selector: "parameter",
223
+ format: ["camelCase"],
224
+ leadingUnderscore: "allow"
225
+ },
226
+ {
227
+ selector: "method",
228
+ format: ["camelCase"]
229
+ },
230
+ {
231
+ selector: "classProperty",
232
+ format: ["camelCase", "UPPER_CASE", "PascalCase"],
233
+ leadingUnderscore: "allow"
234
+ },
235
+ {
236
+ selector: "typeProperty",
237
+ format: ["camelCase"]
238
+ },
239
+ {
240
+ selector: "enum",
241
+ format: ["PascalCase"]
242
+ },
243
+ {
244
+ selector: "enumMember",
245
+ format: ["PascalCase", "UPPER_CASE"]
246
+ }
247
+ ],
248
+ // 禁止没有必要的初始化
249
+ "@typescript-eslint/no-inferrable-types": "error",
250
+ // 函数中未使用await,函数签名不要加async
251
+ "@typescript-eslint/require-await": "error",
252
+ // 没有必要的类型as
253
+ "@typescript-eslint/no-unnecessary-type-assertion": "error",
254
+ // 数组用T[]而不是Array<T>
255
+ "@typescript-eslint/array-type": ["error", { default: "array" }],
256
+ // Promise必须加await或void
257
+ "@typescript-eslint/no-misused-promises": [
258
+ "error",
259
+ {
260
+ checksVoidReturn: false
261
+ }
262
+ ],
263
+ "@typescript-eslint/no-deprecated": "error"
264
+ }
265
+ };
266
+ }
267
+ function tsOnly() {
268
+ return {
269
+ name: "agilebot/ts-only",
270
+ files: TS_GLOBS,
271
+ rules: {
272
+ "prefer-object-has-own": "error",
273
+ "@typescript-eslint/explicit-member-accessibility": "error"
274
+ }
275
+ };
276
+ }
277
+ function jsOnly() {
278
+ return {
279
+ name: "agilebot/js-only",
280
+ files: JS_GLOBS,
281
+ rules: {
282
+ "@typescript-eslint/no-require-imports": "off"
283
+ }
284
+ };
285
+ }
286
+ function dts() {
287
+ return {
288
+ name: "agilebot/dts",
289
+ files: DTS_GLOBS,
290
+ rules: {
291
+ // .d.ts中支持导入ts文件中的类型
292
+ "@typescript-eslint/consistent-type-imports": "off",
293
+ // .d.ts中忽略属性命名规则
294
+ "@typescript-eslint/naming-convention": "off",
295
+ // .d.ts中忽略三斜线引用
296
+ "@typescript-eslint/triple-slash-reference": "off"
297
+ }
298
+ };
299
+ }
300
+
301
+ // src/configs/imports.ts
302
+ import path from "node:path";
303
+ import fs from "node:fs";
304
+ import { findCacheDir, findRootDir, isInEditor as isInEditor2 } from "@agilebot/eslint-utils";
305
+ import pluginImport2 from "eslint-plugin-import-x";
306
+ import pluginNoRelativeImportPaths from "eslint-plugin-no-relative-import-paths";
307
+ function imports(opts) {
308
+ const rootDir = findRootDir(__dirname);
309
+ const pkgPath = path.join(opts.packageDir, "package.json");
310
+ if (!fs.existsSync(pkgPath)) {
311
+ throw new Error(`package.json not found in ${opts.packageDir}`);
312
+ }
313
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
314
+ const tmpPkg = {
315
+ name: `${pkg.name}/tmp`,
316
+ dependencies: {
317
+ [pkg.name]: "*"
318
+ }
319
+ };
320
+ const tmpPkgSafeName = tmpPkg.name.replace(/\//g, "__");
321
+ const cacheDir = findCacheDir(rootDir);
322
+ const tmpPkgDir = path.join(cacheDir, "tmp-pkg", tmpPkgSafeName);
323
+ if (!fs.existsSync(tmpPkgDir)) {
324
+ fs.mkdirSync(tmpPkgDir, { recursive: true });
325
+ }
326
+ const tmpPkgJson = JSON.stringify(tmpPkg, null, 2);
327
+ fs.writeFileSync(path.join(tmpPkgDir, "package.json"), tmpPkgJson);
328
+ return {
329
+ name: "agilebot/imports",
330
+ files: DEFAULT_GLOBS,
331
+ plugins: {
332
+ "import-x": pluginImport2,
333
+ "no-relative-import-paths": pluginNoRelativeImportPaths
334
+ },
335
+ rules: {
336
+ ...pluginImport2.configs.recommended.rules,
337
+ ...pluginImport2.configs.typescript.rules,
338
+ "import-x/no-unresolved": [
339
+ "error",
340
+ {
341
+ ignore: [
342
+ String.raw`\?(react|raw|url|inline|worker|worker&inline|worker&url|sharedworker|sharedworker&inline|sharedworker&url)$`
343
+ ]
344
+ }
345
+ ],
346
+ "import-x/no-named-as-default-member": "off",
347
+ "import-x/no-named-as-default": "off",
348
+ "import-x/no-useless-path-segments": [
349
+ "error",
350
+ {
351
+ noUselessIndex: true
352
+ }
353
+ ],
354
+ "import-x/no-cycle": isInEditor2() ? "off" : "error",
355
+ "import-x/newline-after-import": "error",
356
+ "import-x/first": "error",
357
+ "import-x/no-import-module-exports": "error",
358
+ "import-x/no-anonymous-default-export": [
359
+ "error",
360
+ {
361
+ allowArray: true,
362
+ allowObject: true
363
+ }
364
+ ],
365
+ "import-x/no-extraneous-dependencies": [
366
+ "error",
367
+ {
368
+ packageDir: [opts.packageDir, tmpPkgDir, rootDir],
369
+ devDependencies: [
370
+ "test/**/*",
371
+ "tests/**/*",
372
+ "**/__tests__/**",
373
+ "**/*.test.{ts,tsx,js,jsx,cjs,mjs,mts,cts}",
374
+ "**/*.config.{ts,js,cjs,mjs,mts,cts}",
375
+ "**/.storybook/**",
376
+ "**/*.stories.{ts,tsx}",
377
+ "**/scripts/*.{ts,mts}",
378
+ ...opts.devDependencies ?? []
379
+ ],
380
+ includeInternal: true
381
+ }
382
+ ],
383
+ "import-x/order": [
384
+ "error",
385
+ {
386
+ groups: [
387
+ "builtin",
388
+ "external",
389
+ "internal",
390
+ "parent",
391
+ "sibling",
392
+ "index",
393
+ "object"
394
+ ],
395
+ pathGroups: [
396
+ {
397
+ pattern: `${pkg.name}/**`,
398
+ group: "parent",
399
+ position: "after"
400
+ }
401
+ ],
402
+ "newlines-between": "never",
403
+ distinctGroup: false
404
+ }
405
+ ],
406
+ "no-relative-import-paths/no-relative-import-paths": [
407
+ "warn",
408
+ { allowSameFolder: true }
409
+ ]
410
+ },
411
+ settings: {
412
+ "import-x/parsers": {
413
+ "@typescript-eslint/parser": [".ts", ".tsx"]
414
+ },
415
+ "import-x/resolver": opts.resolver === "oxc" ? {
416
+ oxc: true
417
+ } : {
418
+ typescript: {
419
+ alwaysTryTypes: true
420
+ }
421
+ },
422
+ "import-x/internal-regex": opts.monorepoScope ? `^${opts.monorepoScope.replace(/\//g, "")}/` : void 0,
423
+ "import-x/core-modules": opts.coreModules ?? void 0
424
+ }
425
+ };
426
+ }
427
+
428
+ // src/configs/unicorn.ts
429
+ import pluginUnicorn from "eslint-plugin-unicorn";
430
+ function unicorn(opts) {
431
+ return {
432
+ name: "agilebot/unicorn",
433
+ files: DEFAULT_GLOBS,
434
+ plugins: {
435
+ unicorn: pluginUnicorn
436
+ },
437
+ rules: {
438
+ ...pluginUnicorn.configs["flat/recommended"].rules,
439
+ "unicorn/prefer-module": opts.module ? "error" : "off",
440
+ "unicorn/prefer-top-level-await": "off",
441
+ "unicorn/filename-case": "off",
442
+ "unicorn/import-style": "off",
443
+ "unicorn/prefer-at": "off",
444
+ "unicorn/prevent-abbreviations": "off",
445
+ "unicorn/prefer-date-now": "off",
446
+ "unicorn/no-process-exit": "off",
447
+ "unicorn/no-null": "off",
448
+ "unicorn/consistent-function-scoping": "off",
449
+ "unicorn/numeric-separators-style": "off",
450
+ "unicorn/prefer-optional-catch-binding": "off",
451
+ "unicorn/no-negated-condition": "off",
452
+ "unicorn/switch-case-braces": "off",
453
+ "unicorn/no-array-for-each": "off",
454
+ "unicorn/prefer-ternary": "off",
455
+ "unicorn/better-regex": "off",
456
+ "unicorn/error-message": "off",
457
+ "unicorn/no-object-as-default-parameter": "off",
458
+ "unicorn/no-array-push-push": "off",
459
+ "unicorn/no-useless-undefined": "off",
460
+ "unicorn/prefer-blob-reading-methods": "off",
461
+ "unicorn/catch-error-name": [
462
+ "error",
463
+ {
464
+ name: "err"
465
+ }
466
+ ],
467
+ "unicorn/prefer-global-this": "off"
468
+ }
469
+ };
470
+ }
471
+
472
+ // src/configs/react.ts
473
+ import pluginReact from "eslint-plugin-react";
474
+ import pluginReactX from "@eslint-react/eslint-plugin";
475
+ import pluginReactHooks from "eslint-plugin-react-hooks";
476
+ import pluginJsxA11y from "eslint-plugin-jsx-a11y";
477
+ import pluginStylistic2 from "@stylistic/eslint-plugin";
478
+ import pluginAgilebot from "@agilebot/eslint-plugin";
479
+ function react(opts) {
480
+ return {
481
+ name: "agilebot/react",
482
+ files: DEFAULT_GLOBS,
483
+ plugins: {
484
+ react: pluginReact,
485
+ "react-hooks": pluginReactHooks,
486
+ "jsx-a11y": pluginJsxA11y,
487
+ ...pluginReactX.configs.recommended.plugins,
488
+ "@stylistic": pluginStylistic2,
489
+ "@agilebot": pluginAgilebot
490
+ },
491
+ rules: {
492
+ ...pluginJsxA11y.flatConfigs.recommended.rules,
493
+ // recommended rules from eslint-plugin-react
494
+ "react/no-is-mounted": "error",
495
+ // recommended rules from @eslint-react
496
+ "@eslint-react/no-direct-mutation-state": "error",
497
+ // Children API
498
+ // '@eslint-react/no-children-count': 'warn',
499
+ // '@eslint-react/no-children-for-each': 'warn',
500
+ // '@eslint-react/no-children-map': 'warn',
501
+ // '@eslint-react/no-children-only': 'warn',
502
+ "@eslint-react/no-children-prop": "error",
503
+ "@eslint-react/no-children-to-array": "warn",
504
+ "@eslint-react/no-clone-element": "warn",
505
+ "@eslint-react/no-class-component": "error",
506
+ "@eslint-react/no-string-refs": "error",
507
+ "@eslint-react/no-missing-key": "error",
508
+ "@eslint-react/no-array-index-key": "warn",
509
+ "@eslint-react/no-duplicate-key": "error",
510
+ "@eslint-react/no-comment-textnodes": "error",
511
+ "@eslint-react/no-component-will-mount": "error",
512
+ "@eslint-react/no-component-will-receive-props": "error",
513
+ "@eslint-react/no-component-will-update": "error",
514
+ "@eslint-react/no-unsafe-component-will-mount": "warn",
515
+ "@eslint-react/no-unsafe-component-will-receive-props": "warn",
516
+ "@eslint-react/no-unsafe-component-will-update": "warn",
517
+ // '@eslint-react/no-unstable-context-value': 'error',
518
+ // '@eslint-react/no-unstable-default-props': 'error',
519
+ "@eslint-react/ensure-forward-ref-using-ref": "warn",
520
+ "@eslint-react/no-create-ref": "error",
521
+ "@eslint-react/no-nested-components": "warn",
522
+ "@eslint-react/no-redundant-should-component-update": "error",
523
+ "@eslint-react/no-set-state-in-component-did-mount": "warn",
524
+ "@eslint-react/no-set-state-in-component-did-update": "warn",
525
+ "@eslint-react/no-set-state-in-component-will-update": "warn",
526
+ "@eslint-react/prefer-shorthand-boolean": "error",
527
+ "@eslint-react/no-access-state-in-setstate": "error",
528
+ "@eslint-react/prefer-shorthand-fragment": "error",
529
+ "@eslint-react/no-missing-component-display-name": "error",
530
+ "@eslint-react/no-prop-types": "error",
531
+ "@eslint-react/no-useless-fragment": [
532
+ "error",
533
+ { allowExpressions: true }
534
+ ],
535
+ "@eslint-react/jsx-uses-vars": "error",
536
+ "@eslint-react/jsx-no-duplicate-props": "error",
537
+ // recommended rules from @eslint-react/dom
538
+ "@eslint-react/dom/no-children-in-void-dom-elements": "error",
539
+ "@eslint-react/dom/no-unsafe-target-blank": "error",
540
+ "@eslint-react/dom/no-dangerously-set-innerhtml": "error",
541
+ "@eslint-react/dom/no-dangerously-set-innerhtml-with-children": "error",
542
+ "@eslint-react/dom/no-find-dom-node": "error",
543
+ "@eslint-react/dom/no-render-return-value": "error",
544
+ // recommended rules from @eslint-react/hooks-extra
545
+ "@eslint-react/hooks-extra/prefer-use-state-lazy-initialization": "warn",
546
+ // recommended rules react-hooks
547
+ "react-hooks/rules-of-hooks": "error",
548
+ // recommended rules from @eslint-react/naming-convention
549
+ "@eslint-react/naming-convention/component-name": "error",
550
+ "@eslint-react/naming-convention/use-state": "error",
551
+ // recommended rules from @eslint-react/web-api
552
+ "@eslint-react/web-api/no-leaked-interval": "warn",
553
+ "@eslint-react/web-api/no-leaked-timeout": "warn",
554
+ "@eslint-react/web-api/no-leaked-event-listener": "warn",
555
+ "@eslint-react/web-api/no-leaked-resize-observer": "warn",
556
+ // 以下是自定义规则
557
+ "react/jsx-handler-names": [
558
+ "error",
559
+ {
560
+ eventHandlerPrefix: "handle",
561
+ eventHandlerPropPrefix: "on",
562
+ checkLocalVariables: true
563
+ }
564
+ ],
565
+ "react/no-unused-prop-types": "error",
566
+ // Stylistic rules are not supported by @eslint-react. Use dprint or @stylistic instead.
567
+ "@stylistic/jsx-self-closing-comp": "error",
568
+ // <App prop={'Hello'} />没必要,使用<App prop="Hello" />
569
+ "@stylistic/jsx-curly-brace-presence": [
570
+ "error",
571
+ {
572
+ props: "never",
573
+ children: "never",
574
+ propElementValues: "always"
575
+ }
576
+ ],
577
+ "jsx-a11y/click-events-have-key-events": "off",
578
+ "jsx-a11y/no-static-element-interactions": "off",
579
+ "jsx-a11y/alt-text": "off"
580
+ },
581
+ settings: {
582
+ react: {
583
+ version: typeof opts.version === "string" ? opts.version : "detect"
584
+ }
585
+ }
586
+ };
587
+ }
588
+ function reactJsOnly() {
589
+ return {
590
+ name: "agilebot/react-js-only",
591
+ files: JS_GLOBS,
592
+ rules: {
593
+ // The following can be enforced by TypeScript, no need to implement them
594
+ "react/jsx-no-duplicate-props": "error",
595
+ "react/jsx-no-undef": "error",
596
+ "react/jsx-uses-react": "error",
597
+ "react/no-unescaped-entities": "error",
598
+ "react/no-unknown-property": "error",
599
+ "react/react-in-jsx-scope": "error",
600
+ "react/require-render-return": "error"
601
+ }
602
+ };
603
+ }
604
+
605
+ // src/configs/vue.ts
606
+ import pluginVue from "eslint-plugin-vue";
607
+ function vue(opts) {
608
+ return {
609
+ name: "agilebot/vue",
610
+ files: VUE_GLOBS,
611
+ plugins: {
612
+ vue: pluginVue
613
+ },
614
+ rules: {
615
+ ...opts.version === 3 ? pluginVue.configs["vue3-strongly-recommended"].rules : pluginVue.configs["strongly-recommended"].rules
616
+ }
617
+ };
618
+ }
619
+
620
+ // src/configs/jsdoc.ts
621
+ import pluginJsdoc from "eslint-plugin-jsdoc";
622
+ function jsdoc(opt) {
623
+ return {
624
+ name: "agilebot/jsdoc",
625
+ files: DEFAULT_GLOBS,
626
+ plugins: {
627
+ jsdoc: pluginJsdoc
628
+ },
629
+ rules: {
630
+ ...opt.ts ? pluginJsdoc.configs["flat/recommended-typescript-error"].rules : pluginJsdoc.configs["flat/recommended-error"].rules,
631
+ // 禁止有空行
632
+ "jsdoc/no-blank-block-descriptions": "error",
633
+ "jsdoc/no-blank-blocks": "error",
634
+ // 每行注释都有星号
635
+ "jsdoc/require-asterisk-prefix": "error",
636
+ "jsdoc/check-tag-names": [
637
+ "error",
638
+ {
639
+ typed: opt.ts
640
+ }
641
+ ],
642
+ "jsdoc/require-returns": "off",
643
+ // @return注释不是很有必要
644
+ "jsdoc/require-returns-type": "off"
645
+ }
646
+ };
647
+ }
648
+
649
+ // src/configs/lodash.ts
650
+ import pluginLodash from "eslint-plugin-you-dont-need-lodash-underscore";
651
+
652
+ // ../../node_modules/.pnpm/@eslint+compat@1.2.3_eslint@9.15.0_jiti@2.3.3_/node_modules/@eslint/compat/dist/esm/index.js
653
+ var removedMethodNames = /* @__PURE__ */ new Map([
654
+ ["getSource", "getText"],
655
+ ["getSourceLines", "getLines"],
656
+ ["getAllComments", "getAllComments"],
657
+ ["getDeclaredVariables", "getDeclaredVariables"],
658
+ ["getNodeByRangeIndex", "getNodeByRangeIndex"],
659
+ ["getCommentsBefore", "getCommentsBefore"],
660
+ ["getCommentsAfter", "getCommentsAfter"],
661
+ ["getCommentsInside", "getCommentsInside"],
662
+ ["getJSDocComment", "getJSDocComment"],
663
+ ["getFirstToken", "getFirstToken"],
664
+ ["getFirstTokens", "getFirstTokens"],
665
+ ["getLastToken", "getLastToken"],
666
+ ["getLastTokens", "getLastTokens"],
667
+ ["getTokenAfter", "getTokenAfter"],
668
+ ["getTokenBefore", "getTokenBefore"],
669
+ ["getTokenByRangeStart", "getTokenByRangeStart"],
670
+ ["getTokens", "getTokens"],
671
+ ["getTokensAfter", "getTokensAfter"],
672
+ ["getTokensBefore", "getTokensBefore"],
673
+ ["getTokensBetween", "getTokensBetween"]
674
+ ]);
675
+ var fixedUpRuleReplacements = /* @__PURE__ */ new WeakMap();
676
+ var fixedUpRules = /* @__PURE__ */ new WeakSet();
677
+ var fixedUpPluginReplacements = /* @__PURE__ */ new WeakMap();
678
+ var fixedUpPlugins = /* @__PURE__ */ new WeakSet();
679
+ function fixupRule(ruleDefinition) {
680
+ if (fixedUpRuleReplacements.has(ruleDefinition)) {
681
+ return fixedUpRuleReplacements.get(ruleDefinition);
682
+ }
683
+ const isLegacyRule = typeof ruleDefinition === "function";
684
+ if (!isLegacyRule && fixedUpRules.has(ruleDefinition)) {
685
+ return ruleDefinition;
686
+ }
687
+ const originalCreate = isLegacyRule ? ruleDefinition : ruleDefinition.create.bind(ruleDefinition);
688
+ function ruleCreate(context) {
689
+ if ("getScope" in context) {
690
+ return originalCreate(context);
691
+ }
692
+ const sourceCode = context.sourceCode;
693
+ let currentNode = sourceCode.ast;
694
+ const newContext = Object.assign(Object.create(context), {
695
+ parserServices: sourceCode.parserServices,
696
+ /*
697
+ * The following methods rely on the current node in the traversal,
698
+ * so we need to add them manually.
699
+ */
700
+ getScope() {
701
+ return sourceCode.getScope(currentNode);
702
+ },
703
+ getAncestors() {
704
+ return sourceCode.getAncestors(currentNode);
705
+ },
706
+ markVariableAsUsed(variable) {
707
+ sourceCode.markVariableAsUsed(variable, currentNode);
708
+ }
709
+ });
710
+ for (const [
711
+ contextMethodName,
712
+ sourceCodeMethodName
713
+ ] of removedMethodNames) {
714
+ newContext[contextMethodName] = sourceCode[sourceCodeMethodName].bind(sourceCode);
715
+ }
716
+ Object.freeze(newContext);
717
+ const visitor = originalCreate(newContext);
718
+ for (const [methodName, method] of Object.entries(visitor)) {
719
+ if (methodName.startsWith("on")) {
720
+ visitor[methodName] = (...args) => {
721
+ currentNode = args[methodName === "onCodePathSegmentLoop" ? 2 : 1];
722
+ return method.call(visitor, ...args);
723
+ };
724
+ continue;
725
+ }
726
+ visitor[methodName] = (...args) => {
727
+ currentNode = args[0];
728
+ return method.call(visitor, ...args);
729
+ };
730
+ }
731
+ return visitor;
732
+ }
733
+ const newRuleDefinition = {
734
+ ...isLegacyRule ? void 0 : ruleDefinition,
735
+ create: ruleCreate
736
+ };
737
+ const { schema } = ruleDefinition;
738
+ if (schema) {
739
+ if (!newRuleDefinition.meta) {
740
+ newRuleDefinition.meta = { schema };
741
+ } else {
742
+ newRuleDefinition.meta = {
743
+ ...newRuleDefinition.meta,
744
+ // top-level `schema` had precedence over `meta.schema` so it's okay to overwrite `meta.schema` if it exists
745
+ schema
746
+ };
747
+ }
748
+ }
749
+ fixedUpRuleReplacements.set(ruleDefinition, newRuleDefinition);
750
+ fixedUpRules.add(newRuleDefinition);
751
+ return newRuleDefinition;
752
+ }
753
+ function fixupPluginRules(plugin) {
754
+ if (fixedUpPluginReplacements.has(plugin)) {
755
+ return fixedUpPluginReplacements.get(plugin);
756
+ }
757
+ if (fixedUpPlugins.has(plugin) || !plugin.rules) {
758
+ return plugin;
759
+ }
760
+ const newPlugin = {
761
+ ...plugin,
762
+ rules: Object.fromEntries(
763
+ Object.entries(plugin.rules).map(([ruleId, ruleDefinition]) => [
764
+ ruleId,
765
+ fixupRule(ruleDefinition)
766
+ ])
767
+ )
768
+ };
769
+ fixedUpPluginReplacements.set(plugin, newPlugin);
770
+ fixedUpPlugins.add(newPlugin);
771
+ return newPlugin;
772
+ }
773
+
774
+ // src/configs/lodash.ts
775
+ function lodash() {
776
+ return {
777
+ // lodash一些方法可能影响性能,如forEach等,优先使用js的原生方法
778
+ name: "agilebot/lodash",
779
+ files: DEFAULT_GLOBS,
780
+ plugins: {
781
+ "you-dont-need-lodash-underscore": fixupPluginRules(pluginLodash)
782
+ },
783
+ rules: {
784
+ ...pluginLodash.configs["all-warn"].rules,
785
+ "you-dont-need-lodash-underscore/throttle": "off"
786
+ }
787
+ };
788
+ }
789
+
790
+ // src/configs/comments.ts
791
+ import pluginComments from "@eslint-community/eslint-plugin-eslint-comments";
792
+ function comments() {
793
+ return {
794
+ name: "agilebot/comments",
795
+ files: DEFAULT_GLOBS,
796
+ plugins: {
797
+ "@eslint-community/eslint-comments": pluginComments
798
+ },
799
+ rules: {
800
+ // 禁止未使用的eslint-disable注释
801
+ "@eslint-community/eslint-comments/no-unused-disable": "error",
802
+ // 禁止无限制的eslint-disable注释
803
+ "@eslint-community/eslint-comments/no-unlimited-disable": "error",
804
+ // 禁止重复的eslint-disable注释
805
+ "@eslint-community/eslint-comments/no-duplicate-disable": "error",
806
+ // 禁止聚合的eslint-enable注释
807
+ "@eslint-community/eslint-comments/no-aggregating-enable": "error",
808
+ // 须说明原因eslint-disable
809
+ "@eslint-community/eslint-comments/require-description": [
810
+ "error",
811
+ {
812
+ ignore: ["eslint-env", "exported", "global", "globals"]
813
+ }
814
+ ]
815
+ }
816
+ };
817
+ }
818
+
819
+ // src/configs/cspell.ts
820
+ import pluginCSpell from "@cspell/eslint-plugin";
821
+ function cspell(opts) {
822
+ return {
823
+ name: "agilebot/cspell",
824
+ files: DEFAULT_GLOBS,
825
+ plugins: {
826
+ "@cspell": pluginCSpell
827
+ },
828
+ rules: {
829
+ "@cspell/spellchecker": [
830
+ "warn",
831
+ {
832
+ checkComments: false,
833
+ autoFix: false,
834
+ cspell: opts
835
+ }
836
+ ]
837
+ }
838
+ };
839
+ }
840
+
841
+ // src/configs/agilebot.ts
842
+ import pluginAgilebot2 from "@agilebot/eslint-plugin";
843
+ import pluginReactHooks2 from "eslint-plugin-react-hooks";
844
+ function agilebot(opts) {
845
+ return {
846
+ name: "agilebot/agilebot",
847
+ files: DEFAULT_GLOBS,
848
+ plugins: {
849
+ "@agilebot": pluginAgilebot2,
850
+ "react-hooks": pluginReactHooks2
851
+ },
852
+ rules: {
853
+ ...pluginAgilebot2.configs.recommended.rules,
854
+ "react-hooks/exhaustive-deps": "off",
855
+ "@agilebot/react-better-exhaustive-deps": "warn"
856
+ },
857
+ settings: {
858
+ "agilebot/project-root": opts.root,
859
+ "agilebot/monorepo-scope": opts.monorepoScope ? opts.monorepoScope.replace(/\//g, "") : void 0
860
+ }
861
+ };
862
+ }
863
+
864
+ // src/configs/prettier.ts
865
+ import prettierRecommended from "eslint-plugin-prettier/recommended";
866
+ import pluginPrettier from "eslint-plugin-prettier";
867
+ function prettier() {
868
+ return {
869
+ name: "agilebot/prettier",
870
+ files: DEFAULT_GLOBS,
871
+ plugins: {
872
+ prettier: pluginPrettier
873
+ },
874
+ // Do not extends
875
+ // extends: ['plugin:prettier/recommended'],
876
+ rules: {
877
+ ...prettierRecommended.rules,
878
+ curly: "error",
879
+ "arrow-body-style": "off",
880
+ "prettier/prettier": [
881
+ "error",
882
+ {
883
+ endOfLine: "auto"
884
+ }
885
+ ]
886
+ }
887
+ };
888
+ }
889
+
890
+ // src/configs/godaddy.ts
891
+ import configGodaddy from "eslint-config-godaddy";
892
+ import js from "@eslint/js";
893
+ import pluginMocha from "eslint-plugin-mocha";
894
+ function godaddy() {
895
+ return {
896
+ name: "agilebot/godaddy",
897
+ files: DEFAULT_GLOBS,
898
+ languageOptions: {
899
+ parserOptions: {
900
+ ecmaVersion: 2022,
901
+ sourceType: "module"
902
+ }
903
+ },
904
+ plugins: {
905
+ mocha: pluginMocha
906
+ },
907
+ rules: {
908
+ ...js.configs.recommended.rules,
909
+ ...configGodaddy.rules,
910
+ "quote-props": "off",
911
+ "linebreak-style": "off",
912
+ complexity: "off",
913
+ "max-statements": "off",
914
+ "id-length": "off",
915
+ "default-case": "off",
916
+ "valid-jsdoc": "off",
917
+ "generator-star-spacing": "off",
918
+ "max-params": "off",
919
+ "max-depth": "off",
920
+ "max-len": "off",
921
+ indent: "off",
922
+ "no-undefined": "off",
923
+ "no-process-env": "off",
924
+ "no-sync": "off",
925
+ "no-continue": "off",
926
+ "no-case-declarations": "off",
927
+ "callback-return": "off",
928
+ "unicorn/prefer-string-slice": "off",
929
+ "unicorn/prefer-string-replace-all": "off",
930
+ "new-cap": "off"
931
+ }
932
+ };
933
+ }
934
+
935
+ // src/factory/index.ts
936
+ function factory(root, options) {
937
+ assert.ok(root, "root option is required");
938
+ const tsconfigFiles = findTsconfigFiles(root, {
939
+ absolute: true
940
+ });
941
+ const defaultOptions = {
942
+ jsdoc: true,
943
+ prettier: true,
944
+ lodash: true,
945
+ cspell: {},
946
+ import: true,
947
+ importResolver: "typescript"
948
+ };
949
+ options = {
950
+ ...defaultOptions,
951
+ ...options
952
+ };
953
+ if (options?.config) {
954
+ assert.ok(
955
+ Object.keys(options.config).every(
956
+ (key) => key === "rules" || key === "settings"
957
+ ),
958
+ "config option must only contain rules and settings"
959
+ );
960
+ }
961
+ const commonConfigs = [
962
+ unicorn({
963
+ module: options?.module ?? false
964
+ }),
965
+ comments()
966
+ ];
967
+ if (options.import) {
968
+ commonConfigs.push(
969
+ imports({
970
+ packageDir: root,
971
+ devDependencies: options?.devDependencies,
972
+ monorepoScope: options?.monorepoScope,
973
+ coreModules: options?.coreModules,
974
+ resolver: options?.importResolver
975
+ })
976
+ );
977
+ }
978
+ if (options.prettier) {
979
+ commonConfigs.push(prettier());
980
+ }
981
+ const config = [];
982
+ if (options.godaddy) {
983
+ config.push({
984
+ name: "agilebot/parser",
985
+ files: DEFAULT_GLOBS,
986
+ languageOptions: {
987
+ parser: options.godaddy === "typescript" ? parserTs : void 0,
988
+ parserOptions: {
989
+ project: tsconfigFiles.length > 0 ? tsconfigFiles : true
990
+ }
991
+ }
992
+ });
993
+ config.push(env());
994
+ if (options.jsdoc) {
995
+ config.push(
996
+ jsdoc({
997
+ ts: false
998
+ })
999
+ );
1000
+ }
1001
+ config.push(...commonConfigs);
1002
+ config.push(godaddy());
1003
+ if (options.config) {
1004
+ config.push(options.config);
1005
+ }
1006
+ } else {
1007
+ config.push({
1008
+ name: "agilebot/parser",
1009
+ files: DEFAULT_GLOBS,
1010
+ languageOptions: {
1011
+ parser: !options.vue ? parserTs : parserVue,
1012
+ parserOptions: {
1013
+ parser: parserTs,
1014
+ tsconfigRootDir: root,
1015
+ projectService: true,
1016
+ project: tsconfigFiles.length > 0 ? tsconfigFiles : true,
1017
+ ecmaFeatures: {
1018
+ jsx: true
1019
+ },
1020
+ sourceType: options.module ? "module" : void 0,
1021
+ extraFileExtensions: !options?.vue ? void 0 : [".vue"]
1022
+ }
1023
+ }
1024
+ });
1025
+ config.push(env());
1026
+ config.push(standard());
1027
+ config.push(ts());
1028
+ config.push(jsOnly());
1029
+ config.push(dts());
1030
+ config.push(tsOnly());
1031
+ if (options.react) {
1032
+ config.push(react({ version: options.react }));
1033
+ config.push(reactJsOnly());
1034
+ }
1035
+ if (options.vue) {
1036
+ config.push(
1037
+ vue({
1038
+ version: options.vue
1039
+ })
1040
+ );
1041
+ }
1042
+ if (options.lodash) {
1043
+ config.push(lodash());
1044
+ }
1045
+ if (options.cspell) {
1046
+ config.push(cspell(options.cspell));
1047
+ }
1048
+ if (options.jsdoc) {
1049
+ config.push({
1050
+ ...jsdoc({
1051
+ ts: true
1052
+ }),
1053
+ files: TS_GLOBS
1054
+ });
1055
+ config.push({
1056
+ ...jsdoc({
1057
+ ts: false
1058
+ }),
1059
+ files: JS_GLOBS
1060
+ });
1061
+ }
1062
+ config.push(...commonConfigs);
1063
+ config.push(
1064
+ agilebot({
1065
+ root,
1066
+ monorepoScope: options?.monorepoScope
1067
+ })
1068
+ );
1069
+ if (options.config) {
1070
+ config.push(options.config);
1071
+ }
1072
+ }
1073
+ config.push({
1074
+ name: "agilebot/ignores",
1075
+ ignores: [...IGNORE_GLOBS, ...options.ignores ?? []]
1076
+ });
1077
+ const includedPlugins = /* @__PURE__ */ new Set();
1078
+ config.forEach((configItem) => {
1079
+ if (configItem.plugins) {
1080
+ Object.keys(configItem.plugins).forEach((pluginName) => {
1081
+ if (includedPlugins.has(pluginName)) {
1082
+ delete configItem.plugins[pluginName];
1083
+ } else {
1084
+ includedPlugins.add(pluginName);
1085
+ }
1086
+ });
1087
+ }
1088
+ });
1089
+ return config;
1090
+ }
1091
+ export {
1092
+ factory as agilebot
1093
+ };