@shivaedev/quality 0.32.1 → 0.33.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 +6 -0
- package/README.md +1 -4
- package/dist/rules/builtIn.d.ts +1 -3
- package/dist/rules/builtIn.d.ts.map +1 -1
- package/dist/rules/builtIn.js +0 -2
- package/dist/rules/builtIn.js.map +1 -1
- package/package.json +1 -1
- package/src/rules/builtIn.ts +0 -2
- package/dist/imports/publicModules.d.ts +0 -4
- package/dist/imports/publicModules.d.ts.map +0 -1
- package/dist/imports/publicModules.js +0 -21
- package/dist/imports/publicModules.js.map +0 -1
- package/dist/rules/stories/supportImports.d.ts +0 -4
- package/dist/rules/stories/supportImports.d.ts.map +0 -1
- package/dist/rules/stories/supportImports.js +0 -34
- package/dist/rules/stories/supportImports.js.map +0 -1
- package/src/imports/publicModules.ts +0 -27
- package/src/rules/stories/supportImports.ts +0 -38
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.33.0 - 2026-10-21
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- Remove the `tests/support-imports` rule and its module allowlist. Delete the `tests/support-imports` block from your quality config; configs that still name it fail validation. Story kits may import any workspace module; how tests use those modules belongs to testing guidance and review.
|
|
8
|
+
|
|
3
9
|
## 0.32.1 - 2026-10-21
|
|
4
10
|
|
|
5
11
|
### Changed
|
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ export default defineConfig({
|
|
|
126
126
|
|
|
127
127
|
### Story tests
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
Keep story kits and fixtures in `src/test-support` and keep each spec specific to its story. [`@shivaedev/test-story`](https://github.com/ShivaeDev/platform/tree/main/packages/test-story#readme) explains how to build the kit, traits and verbs over a real engine.
|
|
130
130
|
|
|
131
131
|
Quality's `tests/story-specs` rule reports a test file that declares tests without a kit's `it`, including plain Vitest `it` and `test` declarations mixed with stories. Typecheck tests are exempt, as are test-story itself and its transitive workspace dependencies, including development, optional and peer dependencies: requiring those packages to depend on test-story would create a cycle.
|
|
132
132
|
|
|
@@ -140,8 +140,6 @@ Quality's `tests/story-setup` rule reports top-level test functions named with t
|
|
|
140
140
|
|
|
141
141
|
Specs keep expectations visible. `tests/spec-helpers` moves all module-level helper functions out of specs and into the kit; `tests/no-expect-in-support` moves `expect` calls into the spec. `tests/named-values` rejects numeric literals passed to `toBe` or `toHaveLength` in specs: assert the observed items or give the value a domain name. `tests/no-limit-imports` rejects importing `MAX_*` constants from a `limits` module into specs, so a story proves behavior instead of copying an implementation cap.
|
|
142
142
|
|
|
143
|
-
`tests/support-imports` lets a kit drive any workspace package's exported modules, including its own package's exports through package names or `#` aliases. Export blocks keep internal modules closed. `options.modules` opens additional repository-relative module paths or glob patterns, such as an app's host, schemas and queue definitions. Packages without exports still need that allowlist. Imports within test-support and imports of external packages remain available for the harness; aliases, dynamic imports and re-exports resolve through the same import graph as the other import rules.
|
|
144
|
-
|
|
145
143
|
`boundaries/queue-sql` rejects SQL mentioning the private `pgboss.` schema. Apps use their queue definitions and let workers process jobs; there is no queue-purge API by design. `boundaries/auth-sql` rejects SQL accessing Better Auth's `user`, `account`, `session` and `verification` tables. Apps use platform's auth API; `options.owners` names platform's own auth implementation and its migrations. These rules inspect SQL templates, literal query calls and query variables, and inventoried `.sql` files. They do not evaluate arbitrary runtime SQL construction.
|
|
146
144
|
|
|
147
145
|
`boundaries/http-status` rejects comparisons with HTTP error status numbers, switch cases and literal status-list membership outside `options.edge`. Domain code handles typed errors; the named HTTP edge translates them into transport responses. Process exit codes remain ordinary domain values.
|
|
@@ -153,7 +151,6 @@ export default defineConfig({
|
|
|
153
151
|
rules: {
|
|
154
152
|
"boundaries/auth-sql": { options: { owners: ["platform/auth/**", "platform/auth-migrations/**"] } },
|
|
155
153
|
"boundaries/http-status": { options: { edge: ["src/http/**"] } },
|
|
156
|
-
"tests/support-imports": { options: { modules: ["src/host.ts", "src/schemas.ts", "src/queues.ts"] } },
|
|
157
154
|
},
|
|
158
155
|
});
|
|
159
156
|
```
|
package/dist/rules/builtIn.d.ts
CHANGED
|
@@ -30,9 +30,7 @@ export declare const builtInRules: readonly [import("../rule.ts").Rule<"structur
|
|
|
30
30
|
readonly suites?: readonly string[];
|
|
31
31
|
}>, import("../rule.ts").Rule<"tests/story-setup", undefined>, import("../rule.ts").Rule<"tests/story-specs", undefined>, import("../rule.ts").Rule<"boundaries/queue-sql", undefined>, import("../rule.ts").Rule<"boundaries/auth-sql", {
|
|
32
32
|
readonly owners?: readonly string[];
|
|
33
|
-
}>, import("../rule.ts").Rule<"tests/no-expect-in-support", undefined>, import("../rule.ts").Rule<"tests/spec-helpers", undefined>, import("../rule.ts").Rule<"
|
|
34
|
-
readonly modules?: readonly string[];
|
|
35
|
-
}>, import("../rule.ts").Rule<"boundaries/http-status", {
|
|
33
|
+
}>, import("../rule.ts").Rule<"tests/no-expect-in-support", undefined>, import("../rule.ts").Rule<"tests/spec-helpers", undefined>, import("../rule.ts").Rule<"boundaries/http-status", {
|
|
36
34
|
readonly edge?: readonly string[];
|
|
37
35
|
}>, import("../rule.ts").Rule<"tests/named-values", undefined>, import("../rule.ts").Rule<"tests/no-limit-imports", undefined>];
|
|
38
36
|
//# sourceMappingURL=builtIn.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtIn.d.ts","sourceRoot":"","sources":["../../src/rules/builtIn.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"builtIn.d.ts","sourceRoot":"","sources":["../../src/rules/builtIn.ts"],"names":[],"mappings":"AA0CA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+HA0Cf,CAAC"}
|
package/dist/rules/builtIn.js
CHANGED
|
@@ -25,7 +25,6 @@ import { queueSql } from "#rules/stories/queueSql.ts";
|
|
|
25
25
|
import { storySetup } from "#rules/stories/setup.ts";
|
|
26
26
|
import { specHelpers } from "#rules/stories/specHelpers.ts";
|
|
27
27
|
import { storySpecs } from "#rules/stories/specs.ts";
|
|
28
|
-
import { supportImports } from "#rules/stories/supportImports.ts";
|
|
29
28
|
import { biomeOverrides } from "#rules/suppressions/biomeOverrides.ts";
|
|
30
29
|
import { biomeRecommended } from "#rules/suppressions/biomeRecommended.ts";
|
|
31
30
|
import { noDoubleCast } from "#rules/suppressions/noDoubleCast.ts";
|
|
@@ -79,7 +78,6 @@ export const builtInRules = [
|
|
|
79
78
|
authSql,
|
|
80
79
|
noExpect,
|
|
81
80
|
specHelpers,
|
|
82
|
-
supportImports,
|
|
83
81
|
httpStatus,
|
|
84
82
|
namedValues,
|
|
85
83
|
noLimitImports,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtIn.js","sourceRoot":"","sources":["../../src/rules/builtIn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"builtIn.js","sourceRoot":"","sources":["../../src/rules/builtIn.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/quality",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Repository quality gate with typed rules, a baseline of existing debt and a registry of reasoned exceptions",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/quality#readme",
|
|
6
6
|
"bugs": {
|
package/src/rules/builtIn.ts
CHANGED
|
@@ -25,7 +25,6 @@ import { queueSql } from "#rules/stories/queueSql.ts";
|
|
|
25
25
|
import { storySetup } from "#rules/stories/setup.ts";
|
|
26
26
|
import { specHelpers } from "#rules/stories/specHelpers.ts";
|
|
27
27
|
import { storySpecs } from "#rules/stories/specs.ts";
|
|
28
|
-
import { supportImports } from "#rules/stories/supportImports.ts";
|
|
29
28
|
import { biomeOverrides } from "#rules/suppressions/biomeOverrides.ts";
|
|
30
29
|
import { biomeRecommended } from "#rules/suppressions/biomeRecommended.ts";
|
|
31
30
|
import { noDoubleCast } from "#rules/suppressions/noDoubleCast.ts";
|
|
@@ -80,7 +79,6 @@ export const builtInRules = [
|
|
|
80
79
|
authSql,
|
|
81
80
|
noExpect,
|
|
82
81
|
specHelpers,
|
|
83
|
-
supportImports,
|
|
84
82
|
httpStatus,
|
|
85
83
|
namedValues,
|
|
86
84
|
noLimitImports,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"publicModules.d.ts","sourceRoot":"","sources":["../../src/imports/publicModules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,wBAAsB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAoBxG"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { posix } from "node:path";
|
|
2
|
-
import { exportedModule } from "./packageExports.js";
|
|
3
|
-
import { packageOf } from "./workspace.js";
|
|
4
|
-
export async function publicModules(inputs, graph) {
|
|
5
|
-
const exports = new Map(await Promise.all(graph.packages.map(async (owner) => {
|
|
6
|
-
const manifest = JSON.parse((await inputs.readText(posix.join(owner.directory, "package.json"))) ?? "");
|
|
7
|
-
return [owner, manifest.exports];
|
|
8
|
-
})));
|
|
9
|
-
const modules = new Set();
|
|
10
|
-
for (const edge of graph.edges) {
|
|
11
|
-
if (edge.to.kind !== "file") {
|
|
12
|
-
continue;
|
|
13
|
-
}
|
|
14
|
-
const owner = packageOf(graph.packages, edge.to.path);
|
|
15
|
-
if (owner !== undefined && exportedModule(exports.get(owner), posix.relative(owner.directory, edge.to.path))) {
|
|
16
|
-
modules.add(edge.to.path);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return modules;
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=publicModules.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"publicModules.js","sourceRoot":"","sources":["../../src/imports/publicModules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAkB,EAAE,KAAkB;IACzE,MAAM,OAAO,GAAG,IAAI,GAAG,CACtB,MAAM,OAAO,CAAC,GAAG,CAChB,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAClC,MAAM,QAAQ,GAAmC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACxI,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAU,CAAC;IAC3C,CAAC,CAAC,CACF,CACD,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,SAAS;QACV,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,KAAK,KAAK,SAAS,IAAI,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC9G,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACF,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"supportImports.d.ts","sourceRoot":"","sources":["../../../src/rules/stories/supportImports.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,cAAc;;EA0BzB,CAAC"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect";
|
|
2
|
-
import { importGraph } from "#imports/graph.ts";
|
|
3
|
-
import { publicModules } from "#imports/publicModules.ts";
|
|
4
|
-
import { isTestSupport } from "#naming/testName.ts";
|
|
5
|
-
import { defineRule } from "#rule.ts";
|
|
6
|
-
import { matchesAny } from "./matchesAny.js";
|
|
7
|
-
const SupportImportsOptions = Schema.Struct({
|
|
8
|
-
modules: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
9
|
-
});
|
|
10
|
-
export const supportImports = defineRule({
|
|
11
|
-
check: async ({ options, ...inputs }) => {
|
|
12
|
-
if (!inputs.sources.some((file) => isTestSupport(file.path))) {
|
|
13
|
-
return [];
|
|
14
|
-
}
|
|
15
|
-
const graph = await importGraph(inputs);
|
|
16
|
-
const exported = await publicModules(inputs, graph);
|
|
17
|
-
return graph.edges
|
|
18
|
-
.filter((edge) => isTestSupport(edge.from)
|
|
19
|
-
&& edge.to.kind === "file"
|
|
20
|
-
&& !isTestSupport(edge.to.path)
|
|
21
|
-
&& !exported.has(edge.to.path)
|
|
22
|
-
&& !matchesAny(edge.to.path, options.modules))
|
|
23
|
-
.map((edge) => ({
|
|
24
|
-
file: edge.from,
|
|
25
|
-
line: edge.line,
|
|
26
|
-
message: `Test-support imports "${edge.specifier}" outside its allowed public surface. Drive the app through its host, schemas or queue definitions, or a workspace package's exports; list additional internal module paths in tests/support-imports.options.modules in the repository's quality config.`,
|
|
27
|
-
subject: edge.specifier,
|
|
28
|
-
}));
|
|
29
|
-
},
|
|
30
|
-
description: "Test-support reaches repository modules through workspace package exports and the repository's additional module allowlist.",
|
|
31
|
-
id: "tests/support-imports",
|
|
32
|
-
options: Schema.toStandardSchemaV1(SupportImportsOptions, { parseOptions: { errors: "all", onExcessProperty: "error" } }),
|
|
33
|
-
});
|
|
34
|
-
//# sourceMappingURL=supportImports.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"supportImports.js","sourceRoot":"","sources":["../../../src/rules/stories/supportImports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;CAC5F,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;IACxC,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE;QACvC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC9D,OAAO,EAAE,CAAC;QACX,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACpD,OAAO,KAAK,CAAC,KAAK;aAChB,MAAM,CACN,CAAC,IAAI,EAAE,EAAE,CACR,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;eACrB,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,MAAM;eACvB,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;eAC5B,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;eAC3B,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAC9C;aACA,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,yBAAyB,IAAI,CAAC,SAAS,0PAA0P;YAC1S,OAAO,EAAE,IAAI,CAAC,SAAS;SACvB,CAAC,CAAC,CAAC;IACN,CAAC;IACD,WAAW,EAAE,6HAA6H;IAC1I,EAAE,EAAE,uBAAuB;IAC3B,OAAO,EAAE,MAAM,CAAC,kBAAkB,CAAC,qBAAqB,EAAE,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,CAAC;CACzH,CAAC,CAAC"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { posix } from "node:path";
|
|
2
|
-
import type { RuleInputs } from "#rule.ts";
|
|
3
|
-
import type { ImportGraph } from "./graph.ts";
|
|
4
|
-
import { exportedModule } from "./packageExports.ts";
|
|
5
|
-
import { packageOf } from "./workspace.ts";
|
|
6
|
-
|
|
7
|
-
export async function publicModules(inputs: RuleInputs, graph: ImportGraph): Promise<ReadonlySet<string>> {
|
|
8
|
-
const exports = new Map(
|
|
9
|
-
await Promise.all(
|
|
10
|
-
graph.packages.map(async (owner) => {
|
|
11
|
-
const manifest: { readonly exports?: unknown } = JSON.parse((await inputs.readText(posix.join(owner.directory, "package.json"))) ?? "");
|
|
12
|
-
return [owner, manifest.exports] as const;
|
|
13
|
-
}),
|
|
14
|
-
),
|
|
15
|
-
);
|
|
16
|
-
const modules = new Set<string>();
|
|
17
|
-
for (const edge of graph.edges) {
|
|
18
|
-
if (edge.to.kind !== "file") {
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
const owner = packageOf(graph.packages, edge.to.path);
|
|
22
|
-
if (owner !== undefined && exportedModule(exports.get(owner), posix.relative(owner.directory, edge.to.path))) {
|
|
23
|
-
modules.add(edge.to.path);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return modules;
|
|
27
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect";
|
|
2
|
-
import { importGraph } from "#imports/graph.ts";
|
|
3
|
-
import { publicModules } from "#imports/publicModules.ts";
|
|
4
|
-
import { isTestSupport } from "#naming/testName.ts";
|
|
5
|
-
import { defineRule } from "#rule.ts";
|
|
6
|
-
import { matchesAny } from "./matchesAny.ts";
|
|
7
|
-
|
|
8
|
-
const SupportImportsOptions = Schema.Struct({
|
|
9
|
-
modules: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export const supportImports = defineRule({
|
|
13
|
-
check: async ({ options, ...inputs }) => {
|
|
14
|
-
if (!inputs.sources.some((file) => isTestSupport(file.path))) {
|
|
15
|
-
return [];
|
|
16
|
-
}
|
|
17
|
-
const graph = await importGraph(inputs);
|
|
18
|
-
const exported = await publicModules(inputs, graph);
|
|
19
|
-
return graph.edges
|
|
20
|
-
.filter(
|
|
21
|
-
(edge) =>
|
|
22
|
-
isTestSupport(edge.from)
|
|
23
|
-
&& edge.to.kind === "file"
|
|
24
|
-
&& !isTestSupport(edge.to.path)
|
|
25
|
-
&& !exported.has(edge.to.path)
|
|
26
|
-
&& !matchesAny(edge.to.path, options.modules),
|
|
27
|
-
)
|
|
28
|
-
.map((edge) => ({
|
|
29
|
-
file: edge.from,
|
|
30
|
-
line: edge.line,
|
|
31
|
-
message: `Test-support imports "${edge.specifier}" outside its allowed public surface. Drive the app through its host, schemas or queue definitions, or a workspace package's exports; list additional internal module paths in tests/support-imports.options.modules in the repository's quality config.`,
|
|
32
|
-
subject: edge.specifier,
|
|
33
|
-
}));
|
|
34
|
-
},
|
|
35
|
-
description: "Test-support reaches repository modules through workspace package exports and the repository's additional module allowlist.",
|
|
36
|
-
id: "tests/support-imports",
|
|
37
|
-
options: Schema.toStandardSchemaV1(SupportImportsOptions, { parseOptions: { errors: "all", onExcessProperty: "error" } }),
|
|
38
|
-
});
|