@slip-stream-kit/eslint-plugin 0.11.12 → 0.11.16

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 e2eFileLayout: Rule.RuleModule;
@@ -0,0 +1 @@
1
+ export { e2eFileLayout } from './e2e-file-layout';
@@ -0,0 +1,7 @@
1
+ import type { Rule } from 'eslint';
2
+ export interface Options {
3
+ /** The only tags a test or describe may carry. */
4
+ allowed?: string[];
5
+ }
6
+ export declare const DEFAULT_ALLOWED_TAGS: string[];
7
+ export declare const e2eTestTags: Rule.RuleModule;
@@ -0,0 +1 @@
1
+ export { DEFAULT_ALLOWED_TAGS, e2eTestTags } from './e2e-test-tags';
@@ -0,0 +1,2 @@
1
+ import type { Rule } from 'eslint';
2
+ export declare const e2eTestTitle: Rule.RuleModule;
@@ -0,0 +1 @@
1
+ export { e2eTestTitle } from './e2e-test-title';
@@ -0,0 +1 @@
1
+ export { testLocation } from './test-location';
@@ -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 testLocation: Rule.RuleModule;
@@ -0,0 +1,16 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { CallExpression, ObjectExpression } from 'estree';
3
+ export type PlaywrightCallKind = 'test' | 'describe';
4
+ /**
5
+ * Whether `node` declares a Playwright test or describe block, read from its callee alone.
6
+ *
7
+ * @example
8
+ * playwrightCallKind(parse("test.describe.serial('Checkout', () => {})")) // => 'describe'
9
+ */
10
+ export declare const playwrightCallKind: (node: CallExpression) => PlaywrightCallKind | null;
11
+ /** The `{ tag, annotation }` details object, present only in the three-argument form. */
12
+ export declare const detailsArgument: (node: CallExpression) => ObjectExpression | null;
13
+ /** A title that is a plain string: a literal, or a template without expressions. */
14
+ export declare const staticTitle: (node: CallExpression) => string | null;
15
+ /** True when the linted file belongs to a package whose type resolves to `e2e`. */
16
+ 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.11.12",
4
+ "version": "0.11.16",
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.11.12",
44
+ "@slip-stream-kit/config": "0.11.16",
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
@@ -535,7 +535,7 @@ folder" surfaces in the IDE explorer. The message names the skill that owns that
535
535
  has an owner:
536
536
 
537
537
  ```
538
- `core` is not an allowed `src/` layer for package type `frontend` (allowed: app, features, lib, components, pages, routes). See /infra-kit:fe-architect for the frontend layout.
538
+ `core` is not an allowed `src/` layer for package type `frontend` (allowed: app, features, lib, components, pages, routes, __tests__). See /infra-kit:fe-architect for the frontend layout.
539
539
  `hooks` is not an allowed segment of `features/user` for package type `frontend` (allowed: containers, components, services, __stories__, __tests__). See /infra-kit:fe-architect for the frontend layout.
540
540
  ```
541
541
 
@@ -581,13 +581,13 @@ replaces the whole entry (`layers`, `segments` and `skill`) — there is no merg
581
581
  entry is silent, which is why `mobile` and `lib` report nothing by default: their layouts are not
582
582
  settled.
583
583
 
584
- | Type | Default `layers` | Default `segments` | Default `skill` |
585
- | ---------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------- |
586
- | `frontend` | `app`, `features`, `lib`, `components`, `pages`, `routes` | `features/*` → `containers`, `components`, `services`, `__stories__`, `__tests__` | `/infra-kit:fe-architect` |
587
- | `backend` | `controllers`, `services`, `lib`, `config` | `services/*` → `__tests__` | `/infra-kit:be-architect` |
588
- | `e2e` | `tests`, `pages`, `config`, `lib`, `components`, `mocks`, `fixtures` | `tests/*` → `fixtures`, `data`, `mocks` | `/infra-kit:e2e-architect` |
589
- | `mobile` | — (silent) | — | — |
590
- | `lib` | — (silent) | — | — |
584
+ | Type | Default `layers` | Default `segments` | Default `skill` |
585
+ | ---------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------- |
586
+ | `frontend` | `app`, `features`, `lib`, `components`, `pages`, `routes`, `__tests__` | `features/*` → `containers`, `components`, `services`, `__stories__`, `__tests__` | `/infra-kit:fe-architect` |
587
+ | `backend` | `controllers`, `services`, `lib`, `config`, `__tests__` | `services/*` → `__tests__` | `/infra-kit:be-architect` |
588
+ | `e2e` | `tests`, `visual`, `setup`, `pages`, `config`, `lib`, `components`, `mocks`, `fixtures` | `tests/*`, `visual/*` → `pages`, `fixtures`, `mocks`, `data`, `lib` | `/infra-kit:e2e-architect` |
589
+ | `mobile` | — (silent) | — | — |
590
+ | `lib` | — (silent) | — | — |
591
591
 
592
592
  | Option | Type | Description |
593
593
  | ----------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -628,6 +628,124 @@ override restates every type it wants to change — and only those.
628
628
  stale until those files change. Run without `--cache` in CI if you rely on this rule as a gate.
629
629
  - **The backend skill is a forward reference.** `/infra-kit:be-architect` is named in the default
630
630
  message ahead of the skill shipping; override `backend.skill` if the pointer should go elsewhere.
631
+
632
+ ### `test-location`
633
+
634
+ Require unit tests to be **`*.test.*` files in a `__tests__/` folder beside the code they test**,
635
+ never next to the source file. The file is reported at the top, with the path to move it to:
636
+
637
+ ```
638
+ `slugs.test.ts` sits next to its source. Move it to `src/lib/__tests__/slugs.test.ts` — tests live in a `__tests__/` folder beside the code they test.
639
+ ```
640
+
641
+ Inside a frontend feature (`src/…/features/<name>/`) the only place is the feature root's
642
+ `__tests__/` — the `/infra-kit:fe-architect` layout — so `features/<name>/services/__tests__/` is
643
+ reported too, with `features/<name>/__tests__/` as the target. Elsewhere any `__tests__` segment in
644
+ the path satisfies the rule, so nested folders (`__tests__/fixtures/…`) are fine.
645
+
646
+ `.spec` is reserved for Playwright: a `*.spec.*` file is reported with its `*.test.*` name. Files in
647
+ an `e2e` package (by the same package-type resolution `package-structure` uses) are never reported
648
+ — `e2e-file-layout` owns their layout.
649
+
650
+ ```js
651
+ {
652
+ rules: {
653
+ '@wl/test-location': ['error', { ignore: ['**/*.e2e.test.*'] }],
654
+ },
655
+ }
656
+ ```
657
+
658
+ #### Options
659
+
660
+ | Option | Type | Default | Description |
661
+ | -------- | ---------- | ------- | ---------------------------------------------- |
662
+ | `ignore` | `string[]` | `[]` | Globs; the rule is skipped for matching files. |
663
+
664
+ The recommended preset enables it on test-file names only, with `ignore: ['**/*.e2e.test.*']` for
665
+ e2e suites that sit in a package of another type.
666
+
667
+ ### `e2e-file-layout`
668
+
669
+ Hold an **e2e package** to its file layout: specs are `*.spec.ts` at the root of a domain folder
670
+ (`src/tests/<domain>/` or `src/visual/<domain>/`), and every other file in a domain folder sits in
671
+ one of its subfolders — `pages/`, `fixtures/`, `mocks/`, `data/`, `lib/`. The file is reported once,
672
+ at the top, with where it belongs:
673
+
674
+ ```
675
+ `edge-redirects.test.ts` uses `.test`. Rename it to `edge-redirects.spec.ts` — every Playwright spec in an e2e package is `*.spec.ts`.
676
+ `src/tests/ui/auth/login.spec.ts` nests a spec below its domain folder. Move it to `src/tests/ui/login.spec.ts`, or split the domain into two sibling domains if it holds too many specs.
677
+ `checkout.page.ts` sits in the root of domain `checkout`, which holds only `*.spec.ts`. Move it to `src/tests/checkout/pages/checkout.page.ts`.
678
+ ```
679
+
680
+ The subfolder comes from the suffix: `.page` / `.component` → `pages/`, `.fixture` → `fixtures/`,
681
+ `.mock` → `mocks/`, `.data` → `data/`, anything else → `lib/`. Files outside `src/tests` and
682
+ `src/visual` (shared `src/pages/`, `src/setup/*.setup.ts`, `playwright.config.ts`) are not judged
683
+ beyond the spec checks; which `src/` folders may exist at all is
684
+ [`package-structure`](#package-structure)'s job. Packages of any other type are silent — the type is
685
+ resolved the same way `package-structure` resolves it.
686
+
687
+ ```js
688
+ {
689
+ rules: {
690
+ '@wl/e2e-file-layout': 'error',
691
+ },
692
+ }
693
+ ```
694
+
695
+ #### Options
696
+
697
+ | Option | Type | Default | Description |
698
+ | -------- | ---------- | ------- | ---------------------------------------------- |
699
+ | `ignore` | `string[]` | `[]` | Globs; the rule is skipped for matching files. |
700
+
701
+ ### `e2e-test-tags`
702
+
703
+ Restrict the tags on Playwright `test(…)` and `test.describe(…)` calls in an **e2e package** to an
704
+ allowed set — by default `@smoke`, `@readonly`, `@mocked`, `@slow`. Each unknown tag is reported on
705
+ its own string:
706
+
707
+ ```
708
+ Tag `@mocking` is not an allowed e2e tag. Use one of `@smoke`, `@readonly`, `@mocked`, `@slow`; browsers, devices and environments are Playwright projects, not tags.
709
+ ```
710
+
711
+ Only string literals in the `tag` property of the details object are judged (`{ tag: '@smoke' }`,
712
+ `{ tag: ['@smoke', '@readonly'] }`); a tag held in a shared constant is not resolved. `test.step`
713
+ and hooks carry no tags and are ignored.
714
+
715
+ ```js
716
+ {
717
+ rules: {
718
+ '@wl/e2e-test-tags': ['error', { allowed: ['@smoke', '@readonly', '@mocked', '@slow', '@mobile'] }],
719
+ },
720
+ }
721
+ ```
722
+
723
+ #### Options
724
+
725
+ | Option | Type | Default | Description |
726
+ | --------- | ---------- | --------------------------------------------- | ------------------------------------------------ |
727
+ | `allowed` | `string[]` | `['@smoke', '@readonly', '@mocked', '@slow']` | The only tags allowed. Each must start with `@`. |
728
+
729
+ ### `e2e-test-title`
730
+
731
+ Flag e2e test titles that open with `should`, and suggest the direct form — the title states the
732
+ behaviour and its observable outcome:
733
+
734
+ ```
735
+ Test title "should reject an expired card" starts with `should`. State the behaviour and its observable outcome directly: "reject an expired card".
736
+ ```
737
+
738
+ Only `test(…)` and its `only` / `skip` / `fixme` / `fail` forms with a plain-string title are
739
+ checked; `describe` and `test.step` titles are not. The recommended preset enables it as `error`:
740
+
741
+ ```js
742
+ {
743
+ rules: {
744
+ '@wl/e2e-test-title': 'error',
745
+ },
746
+ }
747
+ ```
748
+
631
749
  ### `max-jsdoc-lines`
632
750
 
633
751
  Cap the height of a JSDoc block. The block's **prose** and its **`@example` bodies**