@shivaedev/quality 0.7.2 → 0.8.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 +23 -0
- package/README.md +102 -8
- package/biome/plugins/constant-names.grit +17 -0
- package/biome/plugins/effect-fn-spans.grit +13 -3
- package/biome/plugins/handler-names.grit +10 -0
- package/biome/plugins/schema-names.grit +13 -0
- package/biome/plugins/schema-struct-keys.grit +7 -0
- package/biome/plugins/service-layers.grit +13 -0
- package/biome/plugins/type-re-exports.grit +8 -0
- package/biome/preset.json +48 -1
- package/dist/baseline/compare.d.ts +1 -1
- package/dist/baseline/compare.d.ts.map +1 -1
- package/dist/baseline/compare.js +1 -1
- package/dist/baseline/compare.js.map +1 -1
- package/dist/baseline/format.d.ts +1 -1
- package/dist/baseline/format.d.ts.map +1 -1
- package/dist/baseline/format.js +2 -2
- package/dist/baseline/format.js.map +1 -1
- package/dist/baseline/legacy.d.ts +2 -2
- package/dist/baseline/legacy.d.ts.map +1 -1
- package/dist/baseline/legacy.js +2 -2
- package/dist/baseline/legacy.js.map +1 -1
- package/dist/baseline/rewrite.js +1 -1
- package/dist/baseline/rewrite.js.map +1 -1
- package/dist/baseline/update.d.ts +1 -1
- package/dist/baseline/update.d.ts.map +1 -1
- package/dist/baseline/update.js +1 -1
- package/dist/baseline/update.js.map +1 -1
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/baseline.d.ts +3 -3
- package/dist/cli/baseline.d.ts.map +1 -1
- package/dist/cli/baseline.js +7 -7
- package/dist/cli/baseline.js.map +1 -1
- package/dist/cli/fix.d.ts +1 -1
- package/dist/cli/fix.d.ts.map +1 -1
- package/dist/cli/fix.js +7 -7
- package/dist/cli/fix.js.map +1 -1
- package/dist/cli/lint.d.ts +2 -2
- package/dist/cli/lint.d.ts.map +1 -1
- package/dist/cli/lint.js +4 -4
- package/dist/cli/lint.js.map +1 -1
- package/dist/cli/migrate.d.ts +1 -1
- package/dist/cli/migrate.d.ts.map +1 -1
- package/dist/cli/migrate.js +9 -9
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/run-main.d.ts +1 -1
- package/dist/cli/run-main.d.ts.map +1 -1
- package/dist/cli/run-main.js +1 -1
- package/dist/cli/run-main.js.map +1 -1
- package/dist/cli/shrink.d.ts +2 -2
- package/dist/cli/shrink.d.ts.map +1 -1
- package/dist/cli/shrink.js +2 -2
- package/dist/cli/shrink.js.map +1 -1
- package/dist/cli.js +7 -7
- package/dist/cli.js.map +1 -1
- package/dist/config/decode.d.ts +2 -2
- package/dist/config/decode.d.ts.map +1 -1
- package/dist/config/decode.js +1 -1
- package/dist/config/decode.js.map +1 -1
- package/dist/config/load.d.ts +2 -2
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +2 -2
- package/dist/config/load.js.map +1 -1
- package/dist/config/resolve.d.ts +3 -3
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +1 -1
- package/dist/config/resolve.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/engine/baseline-file.d.ts +3 -3
- package/dist/engine/baseline-file.d.ts.map +1 -1
- package/dist/engine/baseline-file.js +5 -5
- package/dist/engine/baseline-file.js.map +1 -1
- package/dist/engine/evaluate.d.ts +3 -3
- package/dist/engine/evaluate.d.ts.map +1 -1
- package/dist/engine/evaluate.js +2 -2
- package/dist/engine/evaluate.js.map +1 -1
- package/dist/engine/run-rules.d.ts +2 -2
- package/dist/engine/run-rules.d.ts.map +1 -1
- package/dist/engine/run-rules.js +2 -2
- package/dist/engine/run-rules.js.map +1 -1
- package/dist/engine/session.d.ts +4 -4
- package/dist/engine/session.d.ts.map +1 -1
- package/dist/engine/session.js +6 -6
- package/dist/engine/session.js.map +1 -1
- package/dist/engine/violation.d.ts +2 -2
- package/dist/engine/violation.d.ts.map +1 -1
- package/dist/exceptions/registry.d.ts +2 -2
- package/dist/exceptions/registry.d.ts.map +1 -1
- package/dist/exceptions/registry.js +2 -2
- package/dist/exceptions/registry.js.map +1 -1
- package/dist/git/base.d.ts +1 -1
- package/dist/git/base.d.ts.map +1 -1
- package/dist/git/base.js +1 -1
- package/dist/git/base.js.map +1 -1
- package/dist/git/command.d.ts +1 -1
- package/dist/git/command.d.ts.map +1 -1
- package/dist/git/command.js +1 -1
- package/dist/git/command.js.map +1 -1
- package/dist/git/history.d.ts +1 -1
- package/dist/git/history.d.ts.map +1 -1
- package/dist/imports/departures.d.ts +1 -1
- package/dist/imports/departures.d.ts.map +1 -1
- package/dist/imports/departures.js +1 -1
- package/dist/imports/departures.js.map +1 -1
- package/dist/imports/fences/evaluate.d.ts +2 -2
- package/dist/imports/fences/evaluate.d.ts.map +1 -1
- package/dist/imports/fences/match.d.ts +2 -2
- package/dist/imports/fences/match.d.ts.map +1 -1
- package/dist/imports/fences/match.js +2 -2
- package/dist/imports/fences/match.js.map +1 -1
- package/dist/imports/fences/policy.js +1 -1
- package/dist/imports/fences/policy.js.map +1 -1
- package/dist/imports/fences/reach.d.ts +2 -2
- package/dist/imports/fences/reach.d.ts.map +1 -1
- package/dist/imports/fences/vocabulary.d.ts +1 -1
- package/dist/imports/fences/vocabulary.d.ts.map +1 -1
- package/dist/imports/generated.d.ts +1 -1
- package/dist/imports/generated.d.ts.map +1 -1
- package/dist/imports/generated.js +1 -1
- package/dist/imports/generated.js.map +1 -1
- package/dist/imports/graph.d.ts +1 -1
- package/dist/imports/graph.d.ts.map +1 -1
- package/dist/imports/graph.js +1 -1
- package/dist/imports/graph.js.map +1 -1
- package/dist/imports/resolve.js +1 -1
- package/dist/imports/resolve.js.map +1 -1
- package/dist/imports/workspace.d.ts +1 -1
- package/dist/imports/workspace.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/inventory/collect.d.ts +1 -1
- package/dist/inventory/collect.d.ts.map +1 -1
- package/dist/manifests/sorted.d.ts +1 -1
- package/dist/manifests/sorted.d.ts.map +1 -1
- package/dist/manifests/sorted.js +3 -3
- package/dist/manifests/sorted.js.map +1 -1
- package/dist/naming/exportFits.d.ts +2 -0
- package/dist/naming/exportFits.d.ts.map +1 -0
- package/dist/naming/exportFits.js +20 -0
- package/dist/naming/exportFits.js.map +1 -0
- package/dist/naming/mainExport.d.ts +3 -0
- package/dist/naming/mainExport.d.ts.map +1 -0
- package/dist/naming/mainExport.js +10 -0
- package/dist/naming/mainExport.js.map +1 -0
- package/dist/naming/ownExports.d.ts +8 -0
- package/dist/naming/ownExports.d.ts.map +1 -0
- package/dist/naming/ownExports.js +78 -0
- package/dist/naming/ownExports.js.map +1 -0
- package/dist/naming/packageLayout.d.ts +8 -0
- package/dist/naming/packageLayout.d.ts.map +1 -0
- package/dist/naming/packageLayout.js +57 -0
- package/dist/naming/packageLayout.js.map +1 -0
- package/dist/naming/testName.d.ts +11 -0
- package/dist/naming/testName.d.ts.map +1 -0
- package/dist/naming/testName.js +13 -0
- package/dist/naming/testName.js.map +1 -0
- package/dist/naming/words.d.ts +8 -0
- package/dist/naming/words.d.ts.map +1 -0
- package/dist/naming/words.js +21 -0
- package/dist/naming/words.js.map +1 -0
- package/dist/report/render.d.ts +1 -1
- package/dist/report/render.d.ts.map +1 -1
- package/dist/report/render.js +2 -2
- package/dist/report/render.js.map +1 -1
- package/dist/report/stale.d.ts +1 -1
- package/dist/report/stale.d.ts.map +1 -1
- package/dist/rules/biome.d.ts +1 -1
- package/dist/rules/biome.d.ts.map +1 -1
- package/dist/rules/biome.js +3 -3
- package/dist/rules/biome.js.map +1 -1
- package/dist/rules/built-in.d.ts +13 -1
- package/dist/rules/built-in.d.ts.map +1 -1
- package/dist/rules/built-in.js +24 -14
- package/dist/rules/built-in.js.map +1 -1
- package/dist/rules/comments/kinds.js +1 -1
- package/dist/rules/comments/kinds.js.map +1 -1
- package/dist/rules/comments/max-per-file.d.ts +1 -1
- package/dist/rules/comments/max-per-file.js +2 -2
- package/dist/rules/comments/max-per-file.js.map +1 -1
- package/dist/rules/comments/no-jsdoc.d.ts +1 -1
- package/dist/rules/comments/no-jsdoc.js +1 -1
- package/dist/rules/comments/no-jsdoc.js.map +1 -1
- package/dist/rules/comments/pattern-rule.d.ts +1 -1
- package/dist/rules/comments/pattern-rule.d.ts.map +1 -1
- package/dist/rules/comments/pattern-rule.js +1 -1
- package/dist/rules/comments/pattern-rule.js.map +1 -1
- package/dist/rules/comments/scan.d.ts +1 -1
- package/dist/rules/comments/scan.d.ts.map +1 -1
- package/dist/rules/comments/scan.js +1 -1
- package/dist/rules/comments/scan.js.map +1 -1
- package/dist/rules/files/folderNames.d.ts +5 -0
- package/dist/rules/files/folderNames.d.ts.map +1 -0
- package/dist/rules/files/folderNames.js +74 -0
- package/dist/rules/files/folderNames.js.map +1 -0
- package/dist/rules/files/namedAfterExport.d.ts +4 -0
- package/dist/rules/files/namedAfterExport.d.ts.map +1 -0
- package/dist/rules/files/namedAfterExport.js +76 -0
- package/dist/rules/files/namedAfterExport.js.map +1 -0
- package/dist/rules/files/otherNames.d.ts +5 -0
- package/dist/rules/files/otherNames.d.ts.map +1 -0
- package/dist/rules/files/otherNames.js +99 -0
- package/dist/rules/files/otherNames.js.map +1 -0
- package/dist/rules/imports/aliased.d.ts +1 -1
- package/dist/rules/imports/aliased.d.ts.map +1 -1
- package/dist/rules/imports/aliased.js +2 -2
- package/dist/rules/imports/aliased.js.map +1 -1
- package/dist/rules/imports/cycles.d.ts +1 -1
- package/dist/rules/imports/cycles.d.ts.map +1 -1
- package/dist/rules/imports/cycles.js +4 -4
- package/dist/rules/imports/cycles.js.map +1 -1
- package/dist/rules/imports/fences.d.ts +2 -2
- package/dist/rules/imports/fences.d.ts.map +1 -1
- package/dist/rules/imports/fences.js +3 -3
- package/dist/rules/imports/fences.js.map +1 -1
- package/dist/rules/imports/resolvable.d.ts +1 -1
- package/dist/rules/imports/resolvable.js +3 -3
- package/dist/rules/imports/resolvable.js.map +1 -1
- package/dist/rules/manifests-sorted.d.ts +1 -1
- package/dist/rules/manifests-sorted.d.ts.map +1 -1
- package/dist/rules/manifests-sorted.js +2 -2
- package/dist/rules/manifests-sorted.js.map +1 -1
- package/dist/rules/max-lines.d.ts +1 -1
- package/dist/rules/max-lines.js +1 -1
- package/dist/rules/max-lines.js.map +1 -1
- package/dist/rules/suppressions/biome/configs.d.ts +1 -1
- package/dist/rules/suppressions/biome/configs.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/declarations.d.ts +1 -1
- package/dist/rules/suppressions/biome/declarations.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/declarations.js +1 -1
- package/dist/rules/suppressions/biome/declarations.js.map +1 -1
- package/dist/rules/suppressions/biome/resolve.d.ts +1 -1
- package/dist/rules/suppressions/biome/resolve.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/resolve.js +1 -1
- package/dist/rules/suppressions/biome/resolve.js.map +1 -1
- package/dist/rules/suppressions/biome-overrides.d.ts +1 -1
- package/dist/rules/suppressions/biome-overrides.js +4 -4
- package/dist/rules/suppressions/biome-overrides.js.map +1 -1
- package/dist/rules/suppressions/directives.d.ts +1 -1
- package/dist/rules/suppressions/directives.d.ts.map +1 -1
- package/dist/rules/suppressions/no-double-cast.d.ts +1 -1
- package/dist/rules/suppressions/no-double-cast.d.ts.map +1 -1
- package/dist/rules/suppressions/no-double-cast.js +2 -2
- package/dist/rules/suppressions/no-double-cast.js.map +1 -1
- package/dist/rules/suppressions/no-inline.d.ts +1 -1
- package/dist/rules/suppressions/no-inline.d.ts.map +1 -1
- package/dist/rules/suppressions/no-inline.js +2 -2
- package/dist/rules/suppressions/no-inline.js.map +1 -1
- package/dist/rules/suppressions/stylesheet-comments.d.ts +1 -1
- package/dist/rules/suppressions/stylesheet-comments.d.ts.map +1 -1
- package/dist/rules/suppressions/stylesheet-comments.js +1 -1
- package/dist/rules/suppressions/stylesheet-comments.js.map +1 -1
- package/dist/rules/syntax.d.ts +1 -1
- package/dist/rules/syntax.d.ts.map +1 -1
- package/dist/rules/test-names/colocated.d.ts +4 -0
- package/dist/rules/test-names/colocated.d.ts.map +1 -0
- package/dist/rules/test-names/colocated.js +31 -0
- package/dist/rules/test-names/colocated.js.map +1 -0
- package/dist/rules/test-names/follow.d.ts +4 -0
- package/dist/rules/test-names/follow.d.ts.map +1 -0
- package/dist/rules/test-names/follow.js +66 -0
- package/dist/rules/test-names/follow.js.map +1 -0
- package/dist/rules/test-names/usesDom.d.ts +3 -0
- package/dist/rules/test-names/usesDom.d.ts.map +1 -0
- package/dist/rules/test-names/usesDom.js +18 -0
- package/dist/rules/test-names/usesDom.js.map +1 -0
- package/dist/vitest.d.ts +3 -1
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +11 -11
- package/dist/vitest.js.map +1 -1
- package/package.json +10 -2
- package/src/baseline/compare.ts +1 -1
- package/src/baseline/format.ts +2 -2
- package/src/baseline/legacy.ts +2 -2
- package/src/baseline/rewrite.ts +1 -1
- package/src/baseline/update.ts +1 -1
- package/src/cli/args.ts +1 -1
- package/src/cli/baseline.ts +8 -8
- package/src/cli/fix.ts +7 -7
- package/src/cli/lint.ts +4 -4
- package/src/cli/migrate.ts +9 -9
- package/src/cli/run-main.ts +2 -2
- package/src/cli/shrink.ts +5 -5
- package/src/cli.ts +7 -7
- package/src/config/decode.ts +2 -2
- package/src/config/load.ts +3 -3
- package/src/config/resolve.ts +6 -6
- package/src/config.ts +1 -1
- package/src/engine/baseline-file.ts +6 -6
- package/src/engine/evaluate.ts +3 -3
- package/src/engine/run-rules.ts +3 -3
- package/src/engine/session.ts +6 -6
- package/src/engine/violation.ts +2 -2
- package/src/exceptions/registry.ts +2 -2
- package/src/git/base.ts +1 -1
- package/src/git/command.ts +1 -1
- package/src/git/history.ts +1 -1
- package/src/imports/departures.ts +2 -2
- package/src/imports/fences/evaluate.ts +2 -2
- package/src/imports/fences/match.ts +2 -2
- package/src/imports/fences/policy.ts +2 -2
- package/src/imports/fences/reach.ts +2 -2
- package/src/imports/fences/vocabulary.ts +1 -1
- package/src/imports/generated.ts +2 -2
- package/src/imports/graph.ts +2 -2
- package/src/imports/resolve.ts +1 -1
- package/src/imports/workspace.ts +1 -1
- package/src/index.ts +3 -3
- package/src/inventory/collect.ts +1 -1
- package/src/manifests/sorted.ts +3 -3
- package/src/naming/exportFits.ts +21 -0
- package/src/naming/mainExport.ts +11 -0
- package/src/naming/ownExports.ts +95 -0
- package/src/naming/packageLayout.ts +75 -0
- package/src/naming/testName.ts +25 -0
- package/src/naming/words.ts +28 -0
- package/src/report/render.ts +3 -3
- package/src/report/stale.ts +3 -3
- package/src/rules/biome.ts +3 -3
- package/src/rules/built-in.ts +24 -14
- package/src/rules/comments/kinds.ts +1 -1
- package/src/rules/comments/max-per-file.ts +2 -2
- package/src/rules/comments/no-jsdoc.ts +1 -1
- package/src/rules/comments/pattern-rule.ts +1 -1
- package/src/rules/comments/scan.ts +2 -2
- package/src/rules/files/folderNames.ts +92 -0
- package/src/rules/files/namedAfterExport.ts +87 -0
- package/src/rules/files/otherNames.ts +118 -0
- package/src/rules/imports/aliased.ts +2 -2
- package/src/rules/imports/cycles.ts +4 -4
- package/src/rules/imports/fences.ts +4 -4
- package/src/rules/imports/resolvable.ts +3 -3
- package/src/rules/manifests-sorted.ts +2 -2
- package/src/rules/max-lines.ts +1 -1
- package/src/rules/suppressions/biome/configs.ts +1 -1
- package/src/rules/suppressions/biome/declarations.ts +1 -1
- package/src/rules/suppressions/biome/resolve.ts +2 -2
- package/src/rules/suppressions/biome-overrides.ts +4 -4
- package/src/rules/suppressions/directives.ts +1 -1
- package/src/rules/suppressions/no-double-cast.ts +2 -2
- package/src/rules/suppressions/no-inline.ts +2 -2
- package/src/rules/suppressions/stylesheet-comments.ts +1 -1
- package/src/rules/syntax.ts +1 -1
- package/src/rules/test-names/colocated.ts +34 -0
- package/src/rules/test-names/follow.ts +78 -0
- package/src/rules/test-names/usesDom.ts +22 -0
- package/src/vitest.ts +14 -11
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
|
-
import { defineRule, type Finding } from "
|
|
3
|
-
import { biomeConfigs, type Chain } from "
|
|
4
|
-
import { Declaration, matches, type Scoped, scoped, scopeText } from "
|
|
5
|
-
import { type Weakening, weakeningsOf } from "
|
|
2
|
+
import { defineRule, type Finding } from "#rule.ts";
|
|
3
|
+
import { biomeConfigs, type Chain } from "#rules/suppressions/biome/configs.ts";
|
|
4
|
+
import { Declaration, matches, type Scoped, scoped, scopeText } from "#rules/suppressions/biome/declarations.ts";
|
|
5
|
+
import { type Weakening, weakeningsOf } from "#rules/suppressions/biome/weakenings.ts";
|
|
6
6
|
|
|
7
7
|
const BiomeOverridesOptions = Schema.Struct({
|
|
8
8
|
declared: Schema.Array(Declaration).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { defineRule, type Finding, type SourceFile } from "
|
|
3
|
-
import { parse } from "
|
|
2
|
+
import { defineRule, type Finding, type SourceFile } from "#rule.ts";
|
|
3
|
+
import { parse } from "#rules/syntax.ts";
|
|
4
4
|
|
|
5
5
|
const BRIDGES: ReadonlyMap<ts.SyntaxKind, string> = new Map([
|
|
6
6
|
[ts.SyntaxKind.UnknownKeyword, "unknown"],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineRule, type Finding, type RuleInputs } from "
|
|
2
|
-
import { type SourceComment, scanComments } from "
|
|
1
|
+
import { defineRule, type Finding, type RuleInputs } from "#rule.ts";
|
|
2
|
+
import { type SourceComment, scanComments } from "#rules/comments/scan.ts";
|
|
3
3
|
import { suppressionIn } from "./directives.ts";
|
|
4
4
|
import { STYLESHEET, stylesheetComments } from "./stylesheet-comments.ts";
|
|
5
5
|
|
package/src/rules/syntax.ts
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import ignore from "ignore";
|
|
3
|
+
import { testName } from "#naming/testName.ts";
|
|
4
|
+
import { defineRule, type Finding } from "#rule.ts";
|
|
5
|
+
|
|
6
|
+
const MIRROR_FOLDERS: ReadonlySet<string> = new Set(["__tests__", "spec", "test", "tests"]);
|
|
7
|
+
|
|
8
|
+
const TestsColocatedOptions = Schema.Struct({
|
|
9
|
+
suites: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
function findingOf(path: string): readonly Finding[] {
|
|
13
|
+
const name = testName(path);
|
|
14
|
+
const mirror = name?.folder.split("/").find((folder) => MIRROR_FOLDERS.has(folder));
|
|
15
|
+
if (name === undefined || mirror === undefined) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
return [
|
|
19
|
+
{
|
|
20
|
+
file: path,
|
|
21
|
+
message: `Sits in the test folder "${mirror}/". A test sits beside the file it covers, as ${name.stem}.test${name.extension} beside ${name.stem}.ts, or as a <behaviour>.spec${name.extension} in the folder it covers. A folder of tests that cover several packages is a suite in the "suites" option.`,
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const testsColocated = defineRule({
|
|
27
|
+
check: ({ files, options }) => {
|
|
28
|
+
const suites = ignore().add([...options.suites]);
|
|
29
|
+
return files.filter((path) => !suites.ignores(path)).flatMap(findingOf);
|
|
30
|
+
},
|
|
31
|
+
description: "A test sits beside the code it covers, not in a test, tests, __tests__ or spec folder, unless that folder is a declared suite.",
|
|
32
|
+
id: "tests/colocated",
|
|
33
|
+
options: Schema.toStandardSchemaV1(TestsColocatedOptions, { parseOptions: { errors: "all", onExcessProperty: "error" } }),
|
|
34
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { Effect, Schema } from "effect";
|
|
3
|
+
import ignore from "ignore";
|
|
4
|
+
import { ENVIRONMENTS, type TestName, testName } from "#naming/testName.ts";
|
|
5
|
+
import { CAMEL } from "#naming/words.ts";
|
|
6
|
+
import { defineRule, type Finding, type SourceFile } from "#rule.ts";
|
|
7
|
+
import { usesDom } from "#rules/test-names/usesDom.ts";
|
|
8
|
+
|
|
9
|
+
const ENVIRONMENT_NAMES: ReadonlySet<string> = new Set(ENVIRONMENTS);
|
|
10
|
+
|
|
11
|
+
const FIXTURE_SUFFIXES: ReadonlySet<string> = new Set(["integration", "postgres"]);
|
|
12
|
+
|
|
13
|
+
const CODE = /\.[cm]?[jt]sx?$/u;
|
|
14
|
+
|
|
15
|
+
const GRAMMAR =
|
|
16
|
+
"A test file is <file>[.<environment>].test.ts beside its file or <behaviour>[.<environment>].spec.ts in the folder it covers, with at most one environment of dom, slow and typecheck.";
|
|
17
|
+
|
|
18
|
+
const TestsFollowOptions = Schema.Struct({
|
|
19
|
+
suites: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function siblingsIn(files: readonly string[]): ReadonlySet<string> {
|
|
23
|
+
return new Set(files.filter((file) => CODE.test(file) && testName(file) === undefined).map((file) => file.replace(CODE, "")));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function suffixMessage(file: string, name: TestName): string | undefined {
|
|
27
|
+
const [first, ...rest] = name.modifiers;
|
|
28
|
+
if (first === undefined || (rest.length === 0 && ENVIRONMENT_NAMES.has(first))) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const fixture = name.modifiers.find((modifier) => FIXTURE_SUFFIXES.has(modifier));
|
|
32
|
+
if (fixture !== undefined) {
|
|
33
|
+
return `".${fixture}" is not a test environment. A test that needs a database or a running app takes it from the app's test fixture and is named like any other test. ${GRAMMAR}`;
|
|
34
|
+
}
|
|
35
|
+
return `"${file}" has the suffixes ".${name.modifiers.join(".")}". ${GRAMMAR} An aspect of a module gets its own file in the module's folder, or a .spec.`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function placeMessage(file: string, name: TestName, siblings: ReadonlySet<string>): string | undefined {
|
|
39
|
+
const covered = siblings.has(`${name.folder}/${name.stem}`);
|
|
40
|
+
if (name.kind === "test") {
|
|
41
|
+
return covered
|
|
42
|
+
? undefined
|
|
43
|
+
: `"${file}" follows no file: ${name.stem}.test${name.extension} sits beside ${name.stem}.ts in the same folder. A test that covers the folder as a whole is a <behaviour>.spec${name.extension}, such as checkoutFlow.spec${name.extension}.`;
|
|
44
|
+
}
|
|
45
|
+
if (covered) {
|
|
46
|
+
return `"${file}" shares its name with ${name.stem}.ts. A .spec names a behaviour of its folder, such as checkoutFlow.spec${name.extension}; a test of ${name.stem}.ts is ${name.stem}.test${name.extension}.`;
|
|
47
|
+
}
|
|
48
|
+
return CAMEL.test(name.stem) ? undefined : `"${file}" names its behaviour in camelCase, such as checkoutFlow.spec${name.extension}.`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function environmentMessage(file: string, name: TestName, source: SourceFile): string | undefined {
|
|
52
|
+
if (name.modifiers.includes("dom") || name.modifiers.includes("typecheck") || !usesDom(source)) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
return `"${file}" uses the DOM, so it is ${name.stem}.dom.${name.kind}${name.extension} and runs in the dom project.`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function findingsOf(source: SourceFile, siblings: ReadonlySet<string>): readonly Finding[] {
|
|
59
|
+
const name = testName(source.path);
|
|
60
|
+
if (name === undefined) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
const file = posix.basename(source.path);
|
|
64
|
+
const messages = [suffixMessage(file, name), placeMessage(file, name, siblings), environmentMessage(file, name, source)];
|
|
65
|
+
return messages.flatMap((message) => (message === undefined ? [] : [{ file: source.path, message }]));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const testsFollow = defineRule({
|
|
69
|
+
check: ({ files, options, sources }) => {
|
|
70
|
+
const suites = ignore().add([...options.suites]);
|
|
71
|
+
const siblings = siblingsIn(files);
|
|
72
|
+
return sources.filter((source) => !suites.ignores(source.path)).flatMap((source) => findingsOf(source, siblings));
|
|
73
|
+
},
|
|
74
|
+
description:
|
|
75
|
+
"A .test file follows the file beside it, a .spec names a behaviour of its folder, the only suffix is one environment of dom, slow and typecheck, and a test that uses the DOM is a .dom test.",
|
|
76
|
+
id: "tests/follow",
|
|
77
|
+
options: Schema.toStandardSchemaV1(TestsFollowOptions, { parseOptions: { errors: "all", onExcessProperty: "error" } }),
|
|
78
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { SourceFile } from "#rule.ts";
|
|
3
|
+
import { parse } from "#rules/syntax.ts";
|
|
4
|
+
|
|
5
|
+
const DOM_GLOBALS: ReadonlySet<string> = new Set(["document", "window"]);
|
|
6
|
+
|
|
7
|
+
const TESTING_LIBRARY = "@testing-library/";
|
|
8
|
+
|
|
9
|
+
function touchesDom(node: ts.Node): boolean {
|
|
10
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
11
|
+
return node.moduleSpecifier.text.startsWith(TESTING_LIBRARY);
|
|
12
|
+
}
|
|
13
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && DOM_GLOBALS.has(node.expression.text)) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return ts.forEachChild(node, touchesDom) ?? false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function usesDom(file: SourceFile): boolean {
|
|
20
|
+
const source = parse(file);
|
|
21
|
+
return source === undefined ? false : touchesDom(source);
|
|
22
|
+
}
|
package/src/vitest.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import { defaultExclude, type TestUserConfig } from "vitest/config";
|
|
2
|
+
import type { Environment } from "#naming/testName.ts";
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
-
const DOM = "**/*.dom.test.?(c|m)[jt]s?(x)";
|
|
5
|
-
const SLOW = "**/*.slow.test.?(c|m)[jt]s?(x)";
|
|
6
|
-
const TYPECHECK = "**/*.typecheck.test.?(c|m)[jt]s?(x)";
|
|
7
|
-
const TYPECHECK_ALONE = "**/typecheck.test.?(c|m)[jt]s?(x)";
|
|
4
|
+
const EXTENSION = "?(c|m)[jt]s?(x)";
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
const TYPECHECK_ALONE = `**/typecheck.test.${EXTENSION}`;
|
|
7
|
+
|
|
8
|
+
function named(environment?: Environment): string {
|
|
9
|
+
return environment === undefined ? `**/*.@(test|spec).${EXTENSION}` : `**/*.${environment}.@(test|spec).${EXTENSION}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function excluding(exclude: readonly string[], ...patterns: readonly string[]): string[] {
|
|
13
|
+
return [...defaultExclude, named("typecheck"), TYPECHECK_ALONE, ...exclude, ...patterns];
|
|
11
14
|
}
|
|
12
15
|
|
|
13
|
-
export function testProjects(): TestUserConfig {
|
|
16
|
+
export function testProjects({ exclude = [] }: { readonly exclude?: readonly string[] } = {}): TestUserConfig {
|
|
14
17
|
return {
|
|
15
18
|
project: ["unit", "dom"],
|
|
16
19
|
projects: [
|
|
17
|
-
{ extends: true, test: { environment: "node", exclude: excluding(
|
|
18
|
-
{ extends: true, test: { environment: "happy-dom", exclude: excluding(
|
|
19
|
-
{ extends: true, test: { environment: "node", exclude: excluding(), include: [
|
|
20
|
+
{ extends: true, test: { environment: "node", exclude: excluding(exclude, named("dom"), named("slow")), include: [named()], name: "unit" } },
|
|
21
|
+
{ extends: true, test: { environment: "happy-dom", exclude: excluding(exclude, named("slow")), include: [named("dom")], name: "dom" } },
|
|
22
|
+
{ extends: true, test: { environment: "node", exclude: excluding(exclude), include: [named("slow")], name: "slow" } },
|
|
20
23
|
],
|
|
21
24
|
};
|
|
22
25
|
}
|