lint-suite 1.2.3 → 1.3.0

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 CHANGED
@@ -4,61 +4,76 @@ A comprehensive collection of ESLint Flat configurations for modern web applicat
4
4
 
5
5
  ## Features
6
6
 
7
- - **TypeScript Linting**: Strict typing rules, consistent imports, and code organization
8
- - **Angular Support**: Component best practices (including Signals), template accessibility rules, and modern control flow
9
- - **RxJS Guidelines**: Observable patterns, Finnish notation, and operator safety
7
+ - **TypeScript Linting**: Strict typing rules, v8 type-safety replacements, consistent imports, and code organization
8
+ - **Angular Support**: Component best practices (including Signals), Angular 21+ template rules, and modern control flow
9
+ - **RxJS Guidelines**: Observable patterns, Finnish notation, subject encapsulation, and operator safety
10
10
  - **Code Style**: Formatting rules, line limits, and structural consistency
11
11
  - **Accessibility**: ARIA validation, keyboard events, and semantic HTML
12
- - **Testing**: Jest configurations with appropriate relaxations for test files
13
- - **Additional Support**: JSON, Storybook, and more
12
+ - **Testing**: Jest, Vitest, and Playwright configurations with best-practice rules
13
+ - **Prettier**: Automatic disabling of formatting rules that conflict with Prettier
14
+ - **Architecture**: Module boundary enforcement with `eslint-plugin-boundaries`
15
+ - **Additional Support**: JSON (with comment support for tsconfig), Storybook CSF enforcement
14
16
 
15
17
  ## Installation
16
18
 
17
19
  ```bash
18
- npm install --save-dev lint-suite
20
+ pnpm add -D lint-suite
19
21
  ```
20
22
 
21
23
  ## Dependencies
22
24
 
23
25
  ```bash
24
- npm install --save-dev eslint typescript-eslint eslint-config-prettier
26
+ pnpm add -D eslint typescript-eslint eslint-config-prettier
25
27
  ```
26
28
 
27
29
  ## Usage
28
30
 
29
- Create a `.eslintrc.config.mjs` file in your project root:
31
+ Create an `eslint.config.mjs` file in your project root:
30
32
 
31
33
  ```js
32
- import { base, javascript, typescript } from 'lint-suite';
34
+ import { recommended } from 'lint-suite';
35
+
36
+ export default [...recommended];
37
+ ```
38
+
39
+ Or selectively include configurations:
40
+
41
+ ```js
42
+ import { base, javascript, typescript, prettier } from 'lint-suite';
33
43
 
34
44
  export default [
35
45
  ...base,
36
46
  ...javascript,
37
- ...typescript
38
- // Rest of the required configurations
47
+ ...typescript,
48
+ ...prettier // Must be last to disable conflicting formatting rules
39
49
  ];
40
50
  ```
41
51
 
42
- You can selectively include configurations you need.
43
-
44
52
  ## Available Configurations
45
53
 
46
- - `base`: Core JavaScript rules and formatting
47
- - `typescript`: TypeScript-specific rules
48
- - `angular`: Angular component best practices
49
- - `angularTemplate`: HTML template rules with accessibility focus
50
- - `rxjs`: Observable patterns and operator safety
51
- - `jest`: Testing configurations
52
- - `json`: JSON file linting
53
- - `storybook`: Storybook support
54
- - `boundaries`: Enforce module boundaries (feature, data-access, ui, etc.)
54
+ | Configuration | Description |
55
+ | ------------------- | -------------------------------------------------------- |
56
+ | `base` | Core JavaScript rules, formatting, and complexity limits |
57
+ | `javascript` | JavaScript-specific rules via `@nx/eslint-plugin` |
58
+ | `typescript` | TypeScript strict typing, imports, and naming conventions |
59
+ | `angular` | Angular component best practices with Signal support |
60
+ | `angularTemplate` | HTML template rules with accessibility and performance |
61
+ | `rxjs` | Observable patterns, operator safety, and subscriptions |
62
+ | `jest` | Jest testing best practices and matchers |
63
+ | `vitest` | Vitest testing rules and matcher improvements |
64
+ | `playwright` | Playwright e2e locator and matcher best practices |
65
+ | `json` | JSON linting with comment support for tsconfig/vscode |
66
+ | `storybook` | Storybook CSF enforcement |
67
+ | `boundaries` | Module boundary rules (feature, data-access, ui, etc.) |
68
+ | `prettier` | Disables rules that conflict with Prettier (use last) |
69
+ | **`recommended`** | **All of the above combined in the correct order** |
55
70
 
56
71
  ## Customization
57
72
 
58
73
  You can override any rules by adding a `rules` section to your ESLint config:
59
74
 
60
75
  ```js
61
- import { typescript } from 'lint-suite';
76
+ import { typescript, prettier } from 'lint-suite';
62
77
 
63
78
  export default [
64
79
  ...typescript,
@@ -66,7 +81,8 @@ export default [
66
81
  rules: {
67
82
  '@typescript-eslint/explicit-function-return-type': 'off'
68
83
  }
69
- }
84
+ },
85
+ ...prettier
70
86
  ];
71
87
  ```
72
88
 
@@ -80,9 +96,24 @@ export default [
80
96
 
81
97
  ### eslint-plugin-jest
82
98
 
83
- - `jest/no-disabled-tests`: Disallows disabled tests
84
- - `jest/expect-expect`: Ensures test cases contain at least one expect statement
85
- - `jest/valid-expect`: Validates expect() usage
99
+ - `jest/consistent-test-it`: Enforces consistent test function usage (`it`)
100
+ - `jest/prefer-comparison-matcher`: Enforces comparison matchers
101
+ - `jest/prefer-hooks-on-top`: Ensures hooks are at the top of describe blocks
102
+ - `jest/no-conditional-in-test`: Warns against conditionals in tests
103
+ - ...
104
+
105
+ ### @vitest/eslint-plugin
106
+
107
+ - `vitest/max-nested-describe`: Limits describe nesting depth
108
+ - `vitest/prefer-to-be`: Enforces `toBe` matcher usage
109
+ - `vitest/no-conditional-in-test`: Disallows conditionals in tests
110
+ - ...
111
+
112
+ ### eslint-plugin-playwright
113
+
114
+ - `playwright/prefer-locator`: Enforces modern locator API
115
+ - `playwright/prefer-native-locators`: Prefers native locator methods
116
+ - `playwright/prefer-to-be`: Enforces `toBe` matcher usage
86
117
  - ...
87
118
 
88
119
  ### eslint-plugin-json
@@ -94,22 +125,23 @@ export default [
94
125
  ### @smarttools/eslint-plugin-rxjs
95
126
 
96
127
  - `@rxjs/finnish`: Enforces Finnish notation for observables
97
- - `@rxjs/no-ignored-subscription`: Prevents ignoring returned subscriptions
128
+ - `@rxjs/no-exposed-subjects`: Enforces subject encapsulation
129
+ - `@rxjs/no-cyclic-action`: Prevents infinite loops in NgRx effects
98
130
  - `@rxjs/no-unsafe-takeuntil`: Ensures proper usage of takeUntil operator
99
131
  - ...
100
132
 
101
133
  ### eslint-plugin-storybook
102
134
 
103
- - `storybook/no-redundant-story-name`: Prevents redundant story names
104
- - `storybook/csf-component`: Enforces Component Story Format standards
105
- - `storybook/hierarchy-separator`: Enforces story hierarchy separators
135
+ - `storybook/csf-component`: Enforces component property in stories
136
+ - `storybook/no-stories-of`: Prevents deprecated `storiesOf` API
106
137
  - ...
107
138
 
108
- ### eslint-plugin-import
139
+ ### eslint-plugin-import-x
109
140
 
110
- - `import/no-unresolved`: Ensures imports point to valid modules
111
- - `import/order`: Enforces a consistent order of import statements
112
- - `import/no-duplicates`: Prevents duplicate imports
141
+ - `import-x/no-cycle`: Detects circular dependencies
142
+ - `import-x/no-self-import`: Prevents modules importing themselves
143
+ - `import-x/order`: Enforces a consistent order of import statements
144
+ - `import-x/consistent-type-specifier-style`: Consistent type import style
113
145
  - ...
114
146
 
115
147
  ### @stylistic/eslint-plugin
@@ -119,6 +151,11 @@ export default [
119
151
  - `@stylistic/quotes`: Enforces consistent quote style
120
152
  - ...
121
153
 
154
+ ### eslint-config-prettier
155
+
156
+ - Automatically disables all ESLint rules that conflict with Prettier
157
+ - Must be the last configuration in the array
158
+
122
159
  ## Contributing
123
160
 
124
161
  See [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines.
@@ -128,11 +165,3 @@ See [RELEASE_NOTES.md](./RELEASE_NOTES.md) for detailed release notes.
128
165
  ## License
129
166
 
130
167
  MIT
131
-
132
- ```
133
-
134
- ```
135
-
136
- ```
137
-
138
- ```
package/index.cjs CHANGED
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  jest: () => jest,
39
39
  json: () => json,
40
40
  playwright: () => playwright,
41
+ prettier: () => prettier,
41
42
  recommended: () => recommended,
42
43
  rxjs: () => rxjs,
43
44
  storybook: () => storybook,
@@ -78,6 +79,23 @@ var angularTemplate = (0, import_config.defineConfig)([
78
79
  "@angular-eslint/template/no-nested-tags": "error",
79
80
  "@angular-eslint/template/use-track-by-function": "error",
80
81
  "@angular-eslint/template/label-has-associated-control": "error",
82
+ "@angular-eslint/template/prefer-at-else": "error",
83
+ // v21: @if/@else syntax
84
+ "@angular-eslint/template/prefer-at-empty": "error",
85
+ // v21: @for/@empty syntax
86
+ "@angular-eslint/template/prefer-contextual-for-variables": "error",
87
+ // v21: Use $index, $first, etc.
88
+ "@angular-eslint/template/no-empty-control-flow": "error",
89
+ // v21: Catch incomplete refactoring
90
+ "@angular-eslint/template/prefer-class-binding": "error",
91
+ // v21.2.0: Prefer [class] over ngClass
92
+ "@angular-eslint/template/prefer-static-string-properties": "error",
93
+ // Reduce change detection
94
+ "@angular-eslint/template/conditional-complexity": [
95
+ "warn",
96
+ { maxComplexity: 5 }
97
+ ],
98
+ // Template readability
81
99
  "@angular-eslint/template/attributes-order": [
82
100
  "error",
83
101
  {
@@ -124,7 +142,17 @@ var angular = (0, import_config2.defineConfig)([
124
142
  "@angular-eslint/use-injectable-provided-in": "error",
125
143
  "@angular-eslint/prefer-signal-model": "error",
126
144
  "@angular-eslint/no-uncalled-signals": "error",
127
- "@angular-eslint/prefer-host-metadata-property": "error"
145
+ "@angular-eslint/prefer-host-metadata-property": "error",
146
+ "@angular-eslint/no-implicit-take-until-destroyed": "error",
147
+ // v21.2.0: Enforce explicit DestroyRef
148
+ "@angular-eslint/no-async-lifecycle-method": "error",
149
+ // Prevent async lifecycle hooks
150
+ "@angular-eslint/prefer-output-readonly": "warn",
151
+ // Prevent accidental reassignment
152
+ "@angular-eslint/prefer-output-emitter-ref": "warn",
153
+ // Modern output() function over @Output()
154
+ "@angular-eslint/sort-lifecycle-methods": "warn"
155
+ // Consistent lifecycle method ordering
128
156
  }
129
157
  }
130
158
  ]);
@@ -187,7 +215,10 @@ var base = (0, import_config3.defineConfig)([
187
215
  "no-useless-concat": "error",
188
216
  "prefer-template": "error",
189
217
  "no-nested-ternary": "error",
190
- "no-return-await": "error",
218
+ "no-useless-assignment": "error",
219
+ // NEW: Catch unused assignments (ESLint v9)
220
+ "no-object-constructor": "error",
221
+ // Disallow new Object() without arguments
191
222
  "no-else-return": ["error", { allowElseIf: false }],
192
223
  // Prefer early returns
193
224
  "no-multi-assign": "error",
@@ -369,9 +400,29 @@ var import_config5 = require("eslint/config");
369
400
  var jest = (0, import_config5.defineConfig)([
370
401
  {
371
402
  files: ["**/*.spec.ts", "**/*.spec.js"],
372
- extends: [import_eslint_plugin_jest.default.configs["flat/all"]],
403
+ extends: [import_eslint_plugin_jest.default.configs["flat/recommended"]],
373
404
  rules: {
374
- "jest/no-done-callback": "off"
405
+ "jest/no-done-callback": "off",
406
+ // Elevated from recommended defaults
407
+ "jest/no-focused-tests": "error",
408
+ "jest/no-identical-title": "error",
409
+ "jest/valid-expect": "error",
410
+ // Style rules (selective additions from flat/style)
411
+ "jest/prefer-to-be": "warn",
412
+ "jest/prefer-to-contain": "warn",
413
+ "jest/prefer-to-have-length": "warn",
414
+ // Best practice additions
415
+ "jest/consistent-test-it": ["error", { fn: "it" }],
416
+ "jest/prefer-comparison-matcher": "error",
417
+ "jest/prefer-equality-matcher": "error",
418
+ "jest/prefer-hooks-on-top": "error",
419
+ "jest/prefer-spy-on": "error",
420
+ "jest/prefer-strict-equal": "warn",
421
+ "jest/prefer-mock-promise-shorthand": "error",
422
+ "jest/no-conditional-in-test": "warn",
423
+ "jest/no-duplicate-hooks": "error",
424
+ "jest/no-test-return-statement": "error",
425
+ "jest/require-to-throw-message": "warn"
375
426
  }
376
427
  }
377
428
  ]);
@@ -383,13 +434,22 @@ var json = (0, import_config6.defineConfig)([
383
434
  {
384
435
  files: ["**/*.json"],
385
436
  extends: [import_eslint_plugin_json.default.configs.recommended]
437
+ },
438
+ {
439
+ files: ["**/tsconfig*.json", "**/.vscode/*.json"],
440
+ extends: [import_eslint_plugin_json.default.configs["recommended-with-comments"]]
386
441
  }
387
442
  ]);
388
443
 
444
+ // packages/lint-suite/src/lib/prettier.ts
445
+ var import_eslint_config_prettier = __toESM(require("eslint-config-prettier"), 1);
446
+ var import_config7 = require("eslint/config");
447
+ var prettier = (0, import_config7.defineConfig)([import_eslint_config_prettier.default]);
448
+
389
449
  // packages/lint-suite/src/lib/rxjs.ts
390
450
  var import_eslint_plugin_rxjs = __toESM(require("@smarttools/eslint-plugin-rxjs"), 1);
391
- var import_config7 = require("eslint/config");
392
- var rxjs = (0, import_config7.defineConfig)([
451
+ var import_config8 = require("eslint/config");
452
+ var rxjs = (0, import_config8.defineConfig)([
393
453
  {
394
454
  files: [
395
455
  "**/*.js",
@@ -445,7 +505,13 @@ var rxjs = (0, import_config7.defineConfig)([
445
505
  "rxjs/no-unsafe-first": "error",
446
506
  "rxjs/no-topromise": "error",
447
507
  "rxjs/throw-error": "error",
448
- "rxjs/no-async-subscribe": "off"
508
+ "rxjs/no-async-subscribe": "off",
509
+ "rxjs/no-exposed-subjects": "error",
510
+ // Enforce subject encapsulation
511
+ "rxjs/no-cyclic-action": "error",
512
+ // Prevent infinite loops in NgRx effects
513
+ "rxjs/no-subscribe-handlers": "warn"
514
+ // Prefer observer objects (complements prefer-observer)
449
515
  }
450
516
  },
451
517
  {
@@ -458,12 +524,18 @@ var rxjs = (0, import_config7.defineConfig)([
458
524
 
459
525
  // packages/lint-suite/src/lib/storybook.ts
460
526
  var import_eslint_plugin_storybook = __toESM(require("eslint-plugin-storybook"), 1);
461
- var import_config8 = require("eslint/config");
462
- var storybook = (0, import_config8.defineConfig)([
527
+ var import_config9 = require("eslint/config");
528
+ var storybook = (0, import_config9.defineConfig)([
463
529
  {
464
530
  ignores: ["!.storybook"],
465
531
  files: ["**/*.stories.ts"],
466
- extends: [import_eslint_plugin_storybook.default.configs["flat/recommended"]]
532
+ extends: [import_eslint_plugin_storybook.default.configs["flat/recommended"]],
533
+ rules: {
534
+ "storybook/csf-component": "warn",
535
+ // Ensure component property is set
536
+ "storybook/no-stories-of": "error"
537
+ // Prevent deprecated storiesOf API
538
+ }
467
539
  }
468
540
  ]);
469
541
 
@@ -471,7 +543,7 @@ var storybook = (0, import_config8.defineConfig)([
471
543
  var import_eslint_plugin4 = require("@nx/eslint-plugin");
472
544
  var import_eslint_import_resolver_typescript = require("eslint-import-resolver-typescript");
473
545
  var import_eslint_plugin_import_x2 = __toESM(require("eslint-plugin-import-x"), 1);
474
- var import_config9 = require("eslint/config");
546
+ var import_config10 = require("eslint/config");
475
547
 
476
548
  // packages/lint-suite/src/lib/rules/explicit-accessibility.ts
477
549
  var import_utils = require("@typescript-eslint/utils");
@@ -612,7 +684,7 @@ var localTypescriptRules = {
612
684
  "explicit-accessibility": explicit_accessibility_default
613
685
  }
614
686
  };
615
- var typescript = (0, import_config9.defineConfig)([
687
+ var typescript = (0, import_config10.defineConfig)([
616
688
  // NOTE: Checks for 'prettier' and 'eslint-plugin-prettier'
617
689
  {
618
690
  files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
@@ -638,6 +710,13 @@ var typescript = (0, import_config9.defineConfig)([
638
710
  "@typescript-eslint/no-unsafe-member-access": "error",
639
711
  "@typescript-eslint/no-unsafe-return": "error",
640
712
  "@typescript-eslint/no-unsafe-argument": "error",
713
+ // New v8 type-safety rules (replacements for deprecated ban-types)
714
+ "@typescript-eslint/no-empty-object-type": "error",
715
+ // Bans confusing {} type
716
+ "@typescript-eslint/no-unsafe-function-type": "error",
717
+ // Bans Function type
718
+ "@typescript-eslint/no-wrapper-object-types": "error",
719
+ // Bans Number, String, Boolean wrappers
641
720
  // B. Explicit Annotations (partially covered, explicit module boundaries is key)
642
721
  "@typescript-eslint/explicit-module-boundary-types": "error",
643
722
  // Consider enabling if maximum explicitness is desired, even if verbose:
@@ -658,8 +737,14 @@ var typescript = (0, import_config9.defineConfig)([
658
737
  // E. Best Practices & Potential Errors (Some covered by presets, fine-tuning here)
659
738
  "@typescript-eslint/no-inferrable-types": "warn",
660
739
  // Keep as warn or disable if inference is preferred
661
- "@typescript-eslint/no-var-requires": "error",
662
- // Use ES modules
740
+ "@typescript-eslint/no-require-imports": "error",
741
+ // Use ES modules (replaces deprecated no-var-requires)
742
+ "@typescript-eslint/only-throw-error": "error",
743
+ // Replaces deprecated no-throw-literal
744
+ "@typescript-eslint/no-array-delete": "error",
745
+ // Prevents delete arr[0]
746
+ "@typescript-eslint/return-await": ["error", "in-try-catch"],
747
+ // Better stack traces in try/catch
663
748
  "@typescript-eslint/require-await": "error",
664
749
  "@typescript-eslint/restrict-template-expressions": [
665
750
  "error",
@@ -679,6 +764,32 @@ var typescript = (0, import_config9.defineConfig)([
679
764
  "@typescript-eslint/no-useless-constructor": "error",
680
765
  "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
681
766
  // Prefer dot notation where possible
767
+ // Strict type-checked rules
768
+ "@typescript-eslint/no-unnecessary-condition": "error",
769
+ // Catches always-true/false conditions
770
+ "@typescript-eslint/no-confusing-void-expression": "error",
771
+ // Prevent confusing void usage
772
+ "@typescript-eslint/no-dynamic-delete": "error",
773
+ // Use Map instead of delete obj[key]
774
+ "@typescript-eslint/no-extraneous-class": ["error", { allowWithDecorator: true }],
775
+ // Allow Angular classes
776
+ "@typescript-eslint/no-invalid-void-type": "error",
777
+ // Restrict void to return types
778
+ "@typescript-eslint/unified-signatures": "error",
779
+ // Merge overloads where possible
780
+ "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
781
+ // Forbids foo! ?? bar
782
+ // Stylistic type-checked rules
783
+ "@typescript-eslint/prefer-find": "error",
784
+ // Use find() instead of filter()[0]
785
+ "@typescript-eslint/prefer-for-of": "error",
786
+ // Modern iteration
787
+ "@typescript-eslint/prefer-includes": "error",
788
+ // indexOf() → includes()
789
+ "@typescript-eslint/prefer-string-starts-ends-with": "error",
790
+ // Modern string methods
791
+ "@typescript-eslint/prefer-regexp-exec": "error",
792
+ // Better regex performance
682
793
  // F. Consistency & Style (Some covered by stylistic-type-checked)
683
794
  "@typescript-eslint/consistent-type-assertions": [
684
795
  "error",
@@ -780,10 +891,18 @@ var typescript = (0, import_config9.defineConfig)([
780
891
  "import-x/no-unresolved": "error",
781
892
  "import-x/no-duplicates": "error",
782
893
  "import-x/prefer-default-export": "off",
783
- "import-x/no-useless-path-segments": "error",
894
+ "import-x/no-useless-path-segments": ["error", { noUselessIndex: true }],
784
895
  "import-x/newline-after-import": "error",
785
896
  "import-x/first": "error",
786
- "import-x/no-mutable-exports": "error"
897
+ "import-x/no-mutable-exports": "error",
898
+ "import-x/no-self-import": "error",
899
+ // Prevents modules importing themselves
900
+ "import-x/no-cycle": ["error", { maxDepth: 2, ignoreExternal: true }],
901
+ // Prevents circular dependencies
902
+ "import-x/consistent-type-specifier-style": ["error", "prefer-top-level"],
903
+ // Consistent type imports
904
+ "import-x/no-anonymous-default-export": "error"
905
+ // Improve code searchability
787
906
  },
788
907
  settings: {
789
908
  "import-x/resolver-next": [
@@ -837,38 +956,63 @@ var typescript = (0, import_config9.defineConfig)([
837
956
 
838
957
  // packages/lint-suite/src/lib/vitest.ts
839
958
  var import_eslint_plugin5 = __toESM(require("@vitest/eslint-plugin"), 1);
840
- var import_config10 = require("eslint/config");
959
+ var import_config11 = require("eslint/config");
841
960
  var vitestPlugin = {
842
961
  vitest: import_eslint_plugin5.default
843
962
  };
844
- var vitest = (0, import_config10.defineConfig)([
963
+ var vitest = (0, import_config11.defineConfig)([
845
964
  {
846
965
  files: ["**/*.spec.ts", "**/*.spec.js", "**/*.test.ts", "**/*.test.js"],
847
966
  plugins: vitestPlugin,
848
967
  rules: {
849
968
  ...import_eslint_plugin5.default.configs.recommended.rules,
850
- "vitest/max-nested-describe": ["error", { max: 3 }]
969
+ "vitest/max-nested-describe": ["error", { max: 3 }],
970
+ // Matcher improvements
971
+ "vitest/prefer-to-be": "error",
972
+ "vitest/prefer-to-contain": "error",
973
+ "vitest/prefer-to-have-length": "error",
974
+ "vitest/prefer-comparison-matcher": "error",
975
+ "vitest/prefer-strict-equal": "warn",
976
+ // Test quality
977
+ "vitest/prefer-spy-on": "error",
978
+ "vitest/prefer-hooks-on-top": "error",
979
+ "vitest/prefer-each": "warn",
980
+ "vitest/no-conditional-in-test": "error",
981
+ "vitest/no-test-return-statement": "error",
982
+ "vitest/prefer-mock-promise-shorthand": "error"
851
983
  }
852
984
  }
853
985
  ]);
854
986
 
855
987
  // packages/lint-suite/src/lib/playwright.ts
856
988
  var import_eslint_plugin_playwright = __toESM(require("eslint-plugin-playwright"), 1);
857
- var import_config11 = require("eslint/config");
858
- var playwright = (0, import_config11.defineConfig)([
989
+ var import_config12 = require("eslint/config");
990
+ var playwright = (0, import_config12.defineConfig)([
859
991
  {
860
992
  ...import_eslint_plugin_playwright.default.configs["flat/recommended"],
861
993
  files: ["**/*.e2e.ts", "**/*.e2e.js"],
862
994
  rules: {
863
- ...import_eslint_plugin_playwright.default.configs["flat/recommended"].rules
995
+ ...import_eslint_plugin_playwright.default.configs["flat/recommended"].rules,
996
+ // Locator best practices
997
+ "playwright/prefer-locator": "error",
998
+ "playwright/prefer-native-locators": "error",
999
+ "playwright/no-nth-methods": "warn",
1000
+ // Matcher improvements
1001
+ "playwright/prefer-to-be": "error",
1002
+ "playwright/prefer-to-have-count": "error",
1003
+ "playwright/prefer-to-have-length": "error",
1004
+ "playwright/prefer-comparison-matcher": "error",
1005
+ // Test structure
1006
+ "playwright/prefer-hooks-on-top": "error",
1007
+ "playwright/require-top-level-describe": "warn"
864
1008
  }
865
1009
  }
866
1010
  ]);
867
1011
 
868
1012
  // packages/lint-suite/src/lib/boundaries.ts
869
1013
  var import_eslint_plugin_boundaries = __toESM(require("eslint-plugin-boundaries"), 1);
870
- var import_config12 = require("eslint/config");
871
- var boundaries = (0, import_config12.defineConfig)([
1014
+ var import_config13 = require("eslint/config");
1015
+ var boundaries = (0, import_config13.defineConfig)([
872
1016
  {
873
1017
  files: [
874
1018
  "**/*.js",
@@ -916,6 +1060,8 @@ var boundaries = (0, import_config12.defineConfig)([
916
1060
  },
917
1061
  rules: {
918
1062
  ...import_eslint_plugin_boundaries.default.configs.recommended.rules,
1063
+ "boundaries/no-unknown": "warn",
1064
+ // Warn on imports from uncategorized files
919
1065
  "boundaries/element-types": [
920
1066
  "error",
921
1067
  {
@@ -972,7 +1118,9 @@ var recommended = [
972
1118
  ...boundaries,
973
1119
  ...storybook,
974
1120
  ...vitest,
975
- ...playwright
1121
+ ...playwright,
1122
+ ...prettier
1123
+ // Must be last to disable formatting rules that conflict with Prettier
976
1124
  ];
977
1125
  // Annotate the CommonJS export names for ESM import in node:
978
1126
  0 && (module.exports = {
@@ -984,6 +1132,7 @@ var recommended = [
984
1132
  jest,
985
1133
  json,
986
1134
  playwright,
1135
+ prettier,
987
1136
  recommended,
988
1137
  rxjs,
989
1138
  storybook,