@systemfsoftware/oxlint-plugin-test-discipline 3.8.1 → 4.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @systemfsoftware/oxlint-plugin-test-discipline
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Contract suites are now a recognised kind of behaviour test. A test file with the `contract` suffix may live beside integration suites, and the rules hold it to the same obligations: exactly one Gherkin feature, no bare test runner, and an import of the package it proves.
8
+
9
+ ## 3.9.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Add `expect-boolean-predicate`, which refuses an `expect` on a predicate call, comparison, negation or `&&`/`||` asserted with `toBe(true|false)` and names the `toSatisfy` or `toEqual` rewrite, and `vitest-from-effect-vitest`, which refuses any value import from `vitest` — named, namespace, default, side-effect or dynamic — and names `@effect/vitest` as the rewrite; a type-only import stays legal. `prop-arbitrary-schema-origin` also checks the `of` entries of the object form `it.prop(name, { of, subject, runs }, holds)`.
14
+
3
15
  ## 3.8.1
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -4,19 +4,22 @@ Oxlint rules enforcing property-based test laws, test placement, and test naming
4
4
 
5
5
  ## Rules
6
6
 
7
- | Rule | What it enforces |
8
- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
- | `no-test-file-in-src` | Under `src/`, the only sanctioned test file is a single-segment `<stem>.workflow.property.test.ts` inside a sanctioned test directory, plus the generated `schema-laws.test.ts` entry point. Every other test file is banned: a kernel, policy, or schema suite becomes an in-source `import.meta.vitest` block, and a public-surface test moves outside `src/` as an integration test. |
10
- | `src-property-test-cell` | A property test under `src/` must be a single-segment `<stem>.workflow.property.test.ts` beside the `<stem>.workflow.ts` it covers. A source file whose suffix names a cell listed in `cellsRequiringTest` must also carry an in-source vitest block; that list is empty by default. |
11
- | `test-file-outside-tests-dir` | A test file outside `src/` must live under `tests/`. |
12
- | `test-suffix-outside-src` | Outside `src/`, a test file must end `.integration.test.ts`, `.differential.test.ts`, or `.trace.test.ts` — the three behaviour suffixes. |
13
- | `tests-dir-helpers-in-fixtures` | Under `tests/`, the only non-test modules are helpers and fixtures, and they live inside `tests/__fixtures__/`. |
14
- | `no-io-module-in-source-test` | An in-source `import.meta.vitest` test block is forbidden in a module that performs I/O — decided from the module's own syntax (a non-type import from a filesystem, process or network module, called at least once), never from its filename. Only the in-source-test idiom is judged: a module whose tests live in separate files is a no-op for this rule. |
15
- | `behaviour-test-requires-gherkin` | A `.integration.test.ts` must import `makeFeature` from `@systemfsoftware/effect-gherkin-spec` and must not import test runners directly from `vitest` or `@effect/vitest`. |
16
- | `behaviour-exercises-use-case` | A `.integration.test.ts` must reach at least one shell entry — an executor/handler/adapter/store, the package `main`/`mod`/`index`, or a non-foundation package — so it drives a use case. |
17
- | `behaviour-one-feature-per-file` | A `.integration.test.ts` must contain exactly one `Feature(...)` call; zero or two-or-more is the junk-drawer signal. |
18
- | `differential-test-requires-harness` | A `.differential.test.ts` must import `@systemfsoftware/differential-spec` and invoke its harness; direct `vitest`/`@effect/vitest` imports and raw runner calls (`it`, `test`, `describe`, `it.effect`, and aliases) are forbidden, and importing the harness without invoking it is equally non-compliant. |
19
- | `tests-import-public-api` | Every file under the package-root `tests/` or `__tests__/` trees, regardless of basename, may not relative-import `src` or climb into an `internal` folder. Import the published package name or a sibling helper. |
7
+ | Rule | What it enforces |
8
+ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | `no-test-file-in-src` | Under `src/`, the only sanctioned test file is a single-segment `<stem>.workflow.property.test.ts` inside a sanctioned test directory, plus the generated `schema-laws.test.ts` entry point. Every other test file is banned: a kernel, policy, or schema suite becomes an in-source `import.meta.vitest` block, and a public-surface test moves outside `src/` as an integration test. |
10
+ | `src-property-test-cell` | A property test under `src/` must be a single-segment `<stem>.workflow.property.test.ts` beside the `<stem>.workflow.ts` it covers. A source file whose suffix names a cell listed in `cellsRequiringTest` must also carry an in-source vitest block; that list is empty by default. |
11
+ | `test-file-outside-tests-dir` | A test file outside `src/` must live under `tests/`. |
12
+ | `test-suffix-outside-src` | Outside `src/`, a test file must end `.integration.test.ts`, `.differential.test.ts`, `.trace.test.ts`, or `.conformance.test.ts` — the four sanctioned lane suffixes. A runner-driving package (`vitest`, `vitest-conformance`, `effect-spec-runtime`) is exempt: its plain `*.test.ts` runners and nested-run probes are not consumer lanes. |
13
+ | `tests-dir-helpers-in-fixtures` | Under `tests/`, the only non-test modules are helpers and fixtures, and they live inside `tests/__fixtures__/`. |
14
+ | `no-io-module-in-source-test` | An in-source `import.meta.vitest` test block is forbidden in a module that performs I/O — decided from the module's own syntax (a non-type import from a filesystem, process or network module, called at least once), never from its filename. Only the in-source-test idiom is judged: a module whose tests live in separate files is a no-op for this rule. |
15
+ | `behaviour-test-requires-gherkin` | A `.integration.test.ts` must import `makeFeature` from `@systemfsoftware/effect-gherkin-spec` and must not import test runners directly from `vitest`, `@effect/vitest` or `@systemfsoftware/vitest`. |
16
+ | `behaviour-exercises-use-case` | A `.integration.test.ts` must reach at least one shell entry — an executor/handler/adapter/store, the package `main`/`mod`/`index`, or a non-foundation package — so it drives a use case. |
17
+ | `behaviour-one-feature-per-file` | A `.integration.test.ts` must contain exactly one `Feature(...)` call; zero or two-or-more is the junk-drawer signal. |
18
+ | `differential-test-requires-harness` | A `.differential.test.ts` must import `@systemfsoftware/differential-spec` and invoke its harness; direct `vitest`/`@effect/vitest`/`@systemfsoftware/vitest` imports and raw runner calls (`it`, `test`, `describe`, `it.effect`, and aliases) are forbidden, and importing the harness without invoking it is equally non-compliant. The harness is expressed as `Differential.compare({ name, reference, candidate })` or `Metamorphic.on({ name, system })`. |
19
+ | `conformance-test-requires-harness` | A `.conformance.test.ts` must import `Conformance` from `@systemfsoftware/conformance-spec` and invoke one of its checks — `Conformance.linearizable`, `Conformance.sequential`, or `Conformance.released`; direct `vitest`/`@effect/vitest`/`@systemfsoftware/vitest` imports, raw runner calls (`it`, `test`, `describe`, `it.effect`, and aliases), and the retired `Linearizable.check` / `SequentialModel.check` / `Released.check` shapes are forbidden, and importing the barrel without invoking a check is equally non-compliant. |
20
+ | `model-fixture-imports-subject` | A `*.model.ts` fixture may not import the package whose tests it serves. The package is read from the fixture's path — the directory its tests tree lives in — and an import, re-export, dynamic import, or require of that name, or of any subpath of it, is the implementation reaching its own oracle. A relative specifier is judged the same way lexically: resolved against the fixture's directory it must stay inside the tests tree, so `../../src/Lock.js` is reported and `./Locks.js` is a sibling fixture. `effect`, node builtins, and other packages' names stay allowed. |
21
+ | `vitest-from-systemfsoftware-vitest` | Every value a test uses from Vitest is imported from `@systemfsoftware/vitest`, which re-exports all of Vitest. Any value import from `vitest` or the upstream `@effect/vitest` — named, namespace, default, side-effect or dynamic — is refused; a type-only import stays legal. Exempt: the packages that drive Vitest's own runner instead of the fork (`vitest` itself, `vitest-conformance`, and `effect-spec-runtime`, whose `Register` calls Vitest's option-taking collector). |
22
+ | `tests-import-public-api` | Every file under the package-root `tests/` or `__tests__/` trees, regardless of basename, may not relative-import `src` or climb into an `internal` folder. Import the published package name or a sibling helper. |
20
23
 
21
24
  | suffix | layer | doubles | location |
22
25
  | ----------------------------- | ------------ | ------------------------ | ------------------ |
@@ -24,10 +27,11 @@ Oxlint rules enforcing property-based test laws, test placement, and test naming
24
27
  | `*.integration.test.ts` | Behaviour | permitted, at ports only | NEVER under `src/` |
25
28
  | `*.differential.test.ts` | Differential | permitted, at ports only | NEVER under `src/` |
26
29
  | `*.trace.test.ts` | Trace spec | none — observes graphs | NEVER under `src/` |
30
+ | `*.conformance.test.ts` | Conformance | permitted, at ports only | NEVER under `src/` |
27
31
 
28
32
  ## Enrollment
29
33
 
30
- The rules are turned on by `@systemfsoftware/oxlint-config/base`, which spreads `@systemfsoftware/oxlint-plugin-effect-dmmf`'s recommended set; that aggregate re-exports all nine under the `@systemfsoftware/effect-dmmf/` namespace, so a package extending only `base` already enforces them. `strict` adds three TypeScript rules and nothing from this plugin. Neither preset registers this plugin standalone in `jsPlugins`, so its own `recommended` config is never the thing being loaded.
34
+ `@systemfsoftware/oxlint-config-recommended` loads this plugin in `jsPlugins` and spreads `configs.recommended` into its default `rules` at `error`, so every rule above fires in every package that extends the preset.
31
35
 
32
36
  ## Testing
33
37
 
package/dist/index.d.ts CHANGED
@@ -25,9 +25,12 @@ declare const _default: {
25
25
  'behaviour-one-feature-per-file': import("@oxlint/plugins").Rule;
26
26
  'no-pseudo-gherkin-unit-tests': import("@oxlint/plugins").Rule;
27
27
  'tests-dir-helpers-in-fixtures': import("@oxlint/plugins").Rule;
28
+ 'vitest-from-systemfsoftware-vitest': import("@oxlint/plugins").Rule;
28
29
  'no-io-module-in-source-test': import("@oxlint/plugins").Rule;
29
30
  'tests-import-public-api': import("@oxlint/plugins").Rule;
30
31
  'differential-test-requires-harness': import("@oxlint/plugins").Rule;
32
+ 'conformance-test-requires-harness': import("@oxlint/plugins").Rule;
33
+ 'model-fixture-imports-subject': import("@oxlint/plugins").Rule;
31
34
  'ban-raw-span-name-emit': import("@oxlint/plugins").Rule;
32
35
  'trace-test-requires-taxonomy': import("@oxlint/plugins").Rule;
33
36
  };