@slip-stream-kit/eslint-plugin 0.13.0 → 0.14.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.
@@ -0,0 +1,6 @@
1
+ import type { Rule } from 'eslint';
2
+ export interface Options {
3
+ /** Globs; the rule is skipped for matching files. */
4
+ ignore?: string[];
5
+ }
6
+ export declare const e2eDescribeOrder: Rule.RuleModule;
@@ -0,0 +1 @@
1
+ export { e2eDescribeOrder } from './e2e-describe-order';
@@ -0,0 +1,6 @@
1
+ import type { Rule } from 'eslint';
2
+ export interface Options {
3
+ /** Globs; the rule is skipped for matching files. */
4
+ ignore?: string[];
5
+ }
6
+ export declare const e2eFileOrder: Rule.RuleModule;
@@ -0,0 +1 @@
1
+ export { e2eFileOrder } from './e2e-file-order';
@@ -0,0 +1,6 @@
1
+ import type { Rule } from 'eslint';
2
+ export interface Options {
3
+ /** Globs; the rule is skipped for matching files. */
4
+ ignore?: string[];
5
+ }
6
+ export declare const e2ePageObjectMemberOrder: Rule.RuleModule;
@@ -0,0 +1 @@
1
+ export { e2ePageObjectMemberOrder } from './e2e-page-object-member-order';
@@ -0,0 +1,8 @@
1
+ import type { Rule } from 'eslint';
2
+ export interface Options {
3
+ /** Globs; the rule is skipped for matching files. */
4
+ ignore?: string[];
5
+ /** Top-level `test.describe` blocks a spec may hold. */
6
+ max?: number;
7
+ }
8
+ export declare const e2eTopLevelDescribe: Rule.RuleModule;
@@ -0,0 +1 @@
1
+ export { e2eTopLevelDescribe } from './e2e-top-level-describe';
@@ -0,0 +1,11 @@
1
+ import type { SourceCode } from 'eslint';
2
+ import type * as ESTree from 'estree';
3
+ /**
4
+ * Where `node` starts once its attached leading comments are included: the unbroken run of comments
5
+ * directly above it, each on the line after the previous one ends. A comment separated by a blank
6
+ * line (a file overview, a section banner) stays behind when the node moves.
7
+ *
8
+ * @example
9
+ * attachedStart(sourceCode, node) // => range start of the JSDoc right above `node`, else of `node`
10
+ */
11
+ export declare const attachedStart: (sourceCode: SourceCode, node: ESTree.Node) => number;
@@ -1,6 +1,8 @@
1
1
  import type { Rule } from 'eslint';
2
- import type { CallExpression, ObjectExpression } from 'estree';
2
+ import type { CallExpression, Expression, Node, ObjectExpression } from 'estree';
3
3
  export type PlaywrightCallKind = 'test' | 'describe';
4
+ /** `test.describe.serial` → `['test', 'describe', 'serial']`; null for anything but a plain name chain. */
5
+ export declare const calleeNames: (callee: Expression | Node) => string[] | null;
4
6
  /**
5
7
  * Whether `node` declares a Playwright test or describe block, read from its callee alone.
6
8
  *
@@ -13,4 +15,6 @@ export declare const detailsArgument: (node: CallExpression) => ObjectExpression
13
15
  /** A title that is a plain string: a literal, or a template without expressions. */
14
16
  export declare const staticTitle: (node: CallExpression) => string | null;
15
17
  /** True when the linted file belongs to a package whose type resolves to `e2e`. */
18
+ /** The callee chain of a top-level `test.*(…)` statement, e.g. `['test', 'describe', 'configure']`. */
19
+ export declare const testStatementNames: (statement: Node) => string[] | null;
16
20
  export declare const isInE2ePackage: (context: Rule.RuleContext) => boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slip-stream-kit/eslint-plugin",
3
3
  "type": "module",
4
- "version": "0.13.0",
4
+ "version": "0.14.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ArthurSaenz/infra-kit.git",
@@ -41,7 +41,7 @@
41
41
  "eslint": ">=9"
42
42
  },
43
43
  "devDependencies": {
44
- "@slip-stream-kit/config": "0.13.0",
44
+ "@slip-stream-kit/config": "0.14.0",
45
45
  "@types/node": "^26.5.1",
46
46
  "@typescript-eslint/parser": "^8.70.0",
47
47
  "@wl/eslint-config": "0.1.0",
package/readme.md CHANGED
@@ -698,6 +698,129 @@ resolved the same way `package-structure` resolves it.
698
698
  | -------- | ---------- | ------- | ---------------------------------------------- |
699
699
  | `ignore` | `string[]` | `[]` | Globs; the rule is skipped for matching files. |
700
700
 
701
+ ### `e2e-file-order`
702
+
703
+ Open every **e2e** source file with its main content, so a reader sees it right after the imports:
704
+ `*.page.ts` / `*.component.ts` open with the class, `*.fixture.ts` with the fixtures type and the
705
+ `export const test = base.extend<…>(…)` call, `*.spec.ts` with its first `test.*` call
706
+ (`test.describe`, `test.use`, `test.describe.configure`, …), `*.mock.ts` with its first exported
707
+ function. Constants, helpers and types declared between the imports and that anchor are reported by
708
+ name. A file under a `lib/` folder opens with its exports: a private declaration above any export
709
+ (an `export { … }` list counts) is reported the same way:
710
+
711
+ ```
712
+ `CART_URL` sits between the imports and class `CartPage`. Move it below class `CartPage`: a page object file opens with its imports, then the class. The autofix moves it to the end of the file.
713
+ ```
714
+
715
+ A `const` is not hoisted, so a binding read **while the module loads** stays above the anchor and is
716
+ not reported: a `describe` title, `test.use({…})`, a loop or `forEach` inside a `describe` body, a
717
+ `static` class field, an `extend` option default like `[DEFAULT_LOCALE, { option: true }]` — and
718
+ anything a kept binding reads. Reads inside `test(…)` bodies, hooks, fixture functions, methods and
719
+ instance fields run later and do not pin a binding. `--fix` moves the reported statements, with
720
+ their attached comments and in their original order, to the end of the file; a comment separated
721
+ from the statement by a blank line (a file overview) stays where it is. `*.data.ts` files and
722
+ packages of any other type are not judged.
723
+
724
+ ```js
725
+ {
726
+ rules: {
727
+ '@wl/e2e-file-order': 'error',
728
+ },
729
+ }
730
+ ```
731
+
732
+ #### Options
733
+
734
+ | Option | Type | Default | Description |
735
+ | -------- | ---------- | ------- | ---------------------------------------------- |
736
+ | `ignore` | `string[]` | `[]` | Globs; the rule is skipped for matching files. |
737
+
738
+ ### `e2e-page-object-member-order`
739
+
740
+ Order the members of an **e2e** page object class (`*.page.ts`, `*.component.ts`): fields, the
741
+ constructor, getters, public methods, then private methods. A private or protected getter counts as a
742
+ private method. A property is a field even when it holds an arrow function, since properties
743
+ initialize in source order. Each member out of place is reported with the one it follows:
744
+
745
+ ```
746
+ The public method `goto` comes after the private method `waitForPageList` in class `Catalog2Page`. Order a page object: fields, constructor, getters, public methods, private methods.
747
+ ```
748
+
749
+ `--fix` reorders the class body in one pass. The sort is stable, so members of one group keep their
750
+ relative order, and each member moves with its attached comments.
751
+
752
+ ```js
753
+ {
754
+ rules: {
755
+ '@wl/e2e-page-object-member-order': 'error',
756
+ },
757
+ }
758
+ ```
759
+
760
+ #### Options
761
+
762
+ | Option | Type | Default | Description |
763
+ | -------- | ---------- | ------- | ---------------------------------------------- |
764
+ | `ignore` | `string[]` | `[]` | Globs; the rule is skipped for matching files. |
765
+
766
+ ### `e2e-describe-order`
767
+
768
+ Order the body of every `test.describe` in an **e2e** spec: setup first (`test.use`,
769
+ `test.describe.configure`, `test.setTimeout`, `test.slow`, and `test.skip` / `fixme` / `fail` used
770
+ as a condition, not as a test), then hooks `beforeAll` → `beforeEach` → `afterEach` → `afterAll`,
771
+ then tests and nested describes. Statements that are not `test.*` calls are ignored.
772
+
773
+ ```
774
+ `test.use` (setup) comes after `test('shows the total')` (test) in describe 'Cart'. Order a describe body: `test.use` / `test.describe.configure` / annotations, then hooks beforeAll → beforeEach → afterEach → afterAll, then tests and nested describes.
775
+ ```
776
+
777
+ There is no autofix: moving `test.use({ … })` up past a `const` it reads would put the read in the
778
+ `const`'s TDZ.
779
+
780
+ ```js
781
+ {
782
+ rules: {
783
+ '@wl/e2e-describe-order': 'error',
784
+ },
785
+ }
786
+ ```
787
+
788
+ #### Options
789
+
790
+ | Option | Type | Default | Description |
791
+ | -------- | ---------- | ------- | ---------------------------------------------- |
792
+ | `ignore` | `string[]` | `[]` | Globs; the rule is skipped for matching files. |
793
+
794
+ ### `e2e-top-level-describe`
795
+
796
+ Hold an **e2e** spec to one top-level `test.describe`, with its setup, hooks and tests inside it:
797
+
798
+ ```
799
+ `test.describe('Cart Mutations')` is top-level describe number 2 in this spec; the limit is 1. Move it to its own spec file, or nest it inside `test.describe('Cart')`.
800
+ `test.use` sits at the top level of the spec. Move it inside `test.describe('Cart')`: a spec holds one top-level describe, and its setup, hooks and tests live inside it.
801
+ Test 'shows the total' sits at the top level of the spec. Wrap the spec’s tests in a `test.describe` named after the feature they cover.
802
+ ```
803
+
804
+ When the spec has exactly one top-level describe, `--fix` moves every top-level `test.use`,
805
+ `test.describe.configure`, hook and annotation to the start of its body, in source order and with
806
+ their attached comments; with one describe they apply to the same tests either way. An extra
807
+ describe or a top-level test needs a person: split the file, nest the describe, or wrap the tests.
808
+
809
+ ```js
810
+ {
811
+ rules: {
812
+ '@wl/e2e-top-level-describe': ['error', { max: 1 }],
813
+ },
814
+ }
815
+ ```
816
+
817
+ #### Options
818
+
819
+ | Option | Type | Default | Description |
820
+ | -------- | ---------- | ------- | ------------------------------------------------- |
821
+ | `max` | `integer` | `1` | Top-level `test.describe` blocks a spec may hold. |
822
+ | `ignore` | `string[]` | `[]` | Globs; the rule is skipped for matching files. |
823
+
701
824
  ### `e2e-test-tags`
702
825
 
703
826
  Restrict the tags on Playwright `test(…)` and `test.describe(…)` calls in an **e2e package** to an