@shivaedev/quality 0.19.0 → 0.21.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +7 -22
  3. package/dist/git/command.d.ts +1 -1
  4. package/dist/git/command.d.ts.map +1 -1
  5. package/dist/git/command.js +1 -1
  6. package/dist/git/command.js.map +1 -1
  7. package/dist/hooks/install.d.ts +1 -1
  8. package/dist/hooks/install.d.ts.map +1 -1
  9. package/dist/hooks/location.d.ts +1 -1
  10. package/dist/hooks/location.d.ts.map +1 -1
  11. package/dist/hooks/preCommit.d.ts +1 -1
  12. package/dist/hooks/preCommit.d.ts.map +1 -1
  13. package/dist/hooks/preCommit.js +1 -1
  14. package/dist/hooks/preCommit.js.map +1 -1
  15. package/dist/hooks/uninstall.d.ts +1 -1
  16. package/dist/hooks/uninstall.d.ts.map +1 -1
  17. package/dist/imports/isTooling.d.ts +2 -0
  18. package/dist/imports/isTooling.d.ts.map +1 -0
  19. package/dist/imports/isTooling.js +9 -0
  20. package/dist/imports/isTooling.js.map +1 -0
  21. package/dist/imports/runtime.d.ts.map +1 -1
  22. package/dist/imports/runtime.js +27 -2
  23. package/dist/imports/runtime.js.map +1 -1
  24. package/dist/rules/built-in.d.ts +1 -1
  25. package/dist/rules/built-in.d.ts.map +1 -1
  26. package/dist/rules/built-in.js +2 -0
  27. package/dist/rules/built-in.js.map +1 -1
  28. package/dist/rules/comments/no-environment-pragma.js +1 -1
  29. package/dist/rules/comments/no-environment-pragma.js.map +1 -1
  30. package/dist/rules/files/distinctCase.d.ts +2 -0
  31. package/dist/rules/files/distinctCase.d.ts.map +1 -0
  32. package/dist/rules/files/distinctCase.js +47 -0
  33. package/dist/rules/files/distinctCase.js.map +1 -0
  34. package/dist/rules/imports/manifest.d.ts.map +1 -1
  35. package/dist/rules/imports/manifest.js +2 -8
  36. package/dist/rules/imports/manifest.js.map +1 -1
  37. package/dist/rules/imports/runtime.d.ts.map +1 -1
  38. package/dist/rules/imports/runtime.js +7 -3
  39. package/dist/rules/imports/runtime.js.map +1 -1
  40. package/dist/testProjects.d.ts +3 -0
  41. package/dist/testProjects.d.ts.map +1 -0
  42. package/dist/testProjects.js +25 -0
  43. package/dist/testProjects.js.map +1 -0
  44. package/docs/modules.md +2 -1
  45. package/docs/naming.md +4 -0
  46. package/docs/rules.md +3 -1
  47. package/docs/tooling.md +2 -17
  48. package/package.json +12 -11
  49. package/src/git/command.ts +1 -1
  50. package/src/hooks/preCommit.ts +1 -1
  51. package/src/imports/isTooling.ts +11 -0
  52. package/src/imports/runtime.ts +28 -2
  53. package/src/rules/built-in.ts +2 -0
  54. package/src/rules/comments/no-environment-pragma.ts +1 -1
  55. package/src/rules/files/distinctCase.ts +54 -0
  56. package/src/rules/imports/manifest.ts +2 -10
  57. package/src/rules/imports/runtime.ts +7 -3
  58. package/src/testProjects.ts +30 -0
  59. package/dist/vitest.d.ts +0 -4
  60. package/dist/vitest.d.ts.map +0 -1
  61. package/dist/vitest.js +0 -60
  62. package/dist/vitest.js.map +0 -1
  63. package/src/vitest.ts +0 -65
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.21.0 - 2026-10-16
4
+
5
+ ### Added
6
+
7
+ - `files/distinct-case` reports two files or folders in one folder whose names, or the files they build to, differ only by case, such as `ReadingHistory.tsx` and `readingHistory.ts`. On macOS or Windows such a pair is one path, so a checkout or a build fails. A repository that upgrades records its existing findings with `quality baseline write --rule files/distinct-case`.
8
+
9
+ ## 0.20.0 - 2026-10-13
10
+
11
+ ### Changed
12
+
13
+ - `imports/runtime` treats packages with a nonempty `bin` entry and no runtime folders as server code. Runtime folders take precedence in packages that also ship browser code.
14
+ - Package-root scripts, tooling folders and JavaScript or TypeScript config files are server code; client and shared code cannot import them.
15
+ - The runtime rule loads the browser-global checker only when shared source needs checking, avoiding DOM declaration parsing during Node-only CLI startup.
16
+
17
+ ### Breaking
18
+
19
+ - Requires stable Effect 4.0.4 in place of 4.0.0-rc.112. Effect 4.0.4 moves the former `effect/unstable/*` modules to `effect/*` and renames constructors such as `Config.string` to `Config.String`. Install `@effect/platform-node` and `@effect/platform-node-shared` 4.0.4 and Vitest 5 alongside it.
20
+ - Removes `inheritTags`. Vitest 5 gives an inline project the tags of the config file it `extends`, so a root config passes its projects to `projects` directly.
21
+ - Moves `testProjects` from `@shivaedev/quality/vitest.ts` to `@shivaedev/quality/testProjects.ts`. Change the import in each `vitest.config.ts`.
22
+
3
23
  ## 0.19.0 - 2026-10-12
4
24
 
5
25
  ### Added
package/README.md CHANGED
@@ -80,11 +80,13 @@ When a config exists, its folder is the root for paths and hook scripts. Without
80
80
 
81
81
  ### 2. When architecture needs it: describe an import boundary
82
82
 
83
- An app says where its code runs through folder names. A package adopts the runtime convention by having `src/client/` or `src/server/`; no config entry is needed. In that package, `src/client/` is browser code, `src/server/` is server code, and everything else is shared. Keep shared code wherever its topic belongs; there is no required `src/shared/` folder or runtime file suffix.
83
+ An app says where its code runs through folder names. A package adopts the runtime convention by having `src/client/` or `src/server/`; no config entry is needed. In that package, `src/client/` is browser code, `src/server/` is server code, and everything else is shared except package-root tooling. Keep shared code wherever its topic belongs; there is no required `src/shared/` folder or runtime file suffix.
84
84
 
85
85
  `imports/runtime` rejects client imports of server code or Node built-ins. Shared code may import neither client nor server code, use browser globals such as `window`, `document` or `localStorage`, or import Node built-ins. Both client and server code may import shared code. The check includes type imports and re-exports and resolves aliases through the shared import graph. Locally bound names and property names are not browser globals; portable web APIs such as `URL`, `fetch` and `AbortController` remain available to shared code. Test files and `test-support/` ship nowhere and are outside this runtime policy.
86
86
 
87
- Adoption is per package: packages without either runtime folder retain their existing policies. Existing explicit fences continue to run in both adopted and legacy packages, so hand-kept browser, server and Markdown lists can remain until their package moves. Runtime folders are detected independently of `sources`, including empty folders; `sources` still selects the code that is checked.
87
+ A package with a nonempty `bin` entry and no runtime folders is server code throughout. Runtime folders take precedence when a package also ships browser code. A Node library without a CLI uses `src/server/`; `engines.node` alone does not say that a package is Node-only. Packages without runtime folders or a `bin` entry retain their existing source policies. Existing explicit fences continue to run in every package. Runtime folders are detected independently of `sources`, including empty folders; `sources` still selects the code that is checked.
88
+
89
+ Tooling is server code in every package, including the workspace root: files under its top-level `script/`, `scripts/` and `tooling/` folders, and top-level JavaScript or TypeScript config files such as `vitest.config.ts`. A tooling folder or config file nested under `src/` follows the source runtime policy. Browser and shared code cannot import package-root tooling.
88
90
 
89
91
  The manifest owns ordinary workspace dependencies. When a package promises more, put `quality.fences.config.ts` beside its `package.json`, exporting an array of fences as the default. Quality discovers this file at the repository root and in workspace packages, even when `sources` includes only their source folders. The root config does not list boundary files.
90
92
 
@@ -152,7 +154,7 @@ Import names from their defining module; there is no root entry. The package's `
152
154
  | `imports/fences/dsl.ts` | `fence` |
153
155
  | `imports/fences/selectors.ts` | `packages`, `folders`, `files`, `modules`, `scopes`, `anyOf`, `workspace`, `anything`, `external` |
154
156
  | `imports/fences/model.ts` | `Fence`, `Target`, `Selector`, `Prohibition`, `Examples`, `Chain`, `ExampleStep`, `External` |
155
- | `vitest.ts` | `testProjects`, `inheritTags` |
157
+ | `testProjects.ts` | `testProjects` |
156
158
  | `naming/testName.ts` | `testName`, `isTestCode`, `isTestSupport`, `ENVIRONMENTS`, `Environment`, `TestName` |
157
159
 
158
160
  #### Config
@@ -206,7 +208,7 @@ quality hooks pre-commit [--config <file>]
206
208
  ### Install, shared tooling and limits
207
209
 
208
210
  ```sh
209
- pnpm add --save-dev @shivaedev/quality @effect/platform-node@4.0.0-rc.112 @effect/platform-node-shared@4.0.0-rc.112 effect@4.0.0-rc.112
211
+ pnpm add --save-dev @shivaedev/quality @effect/platform-node@4.0.4 @effect/platform-node-shared@4.0.4 effect@4.0.4
210
212
  ```
211
213
 
212
214
  Node 24 or later is required. The CLI loads the TypeScript config through Node's native import; use erasable syntax and `.ts` extensions for relative TypeScript imports. Installing the package does not install a hook; opt in with `quality hooks install`.
@@ -216,7 +218,7 @@ The package includes `@shivaedev/quality/biome`, `@shivaedev/quality/tsconfig/ba
216
218
  For Vitest, install `vitest` and `happy-dom` when the repository has DOM tests, then use:
217
219
 
218
220
  ```ts
219
- import { testProjects } from "@shivaedev/quality/vitest.ts";
221
+ import { testProjects } from "@shivaedev/quality/testProjects.ts";
220
222
  import { defineConfig } from "vitest/config";
221
223
 
222
224
  export default defineConfig({ test: testProjects() });
@@ -239,23 +241,6 @@ const integration = test.skipIf(databaseUrl === undefined);
239
241
 
240
242
  `databaseUrl` is the test database URL read by the repository's environment helper. Declare the real PostgreSQL tests with `integration(name, body)`. A conditionally registered suite or Effect tester follows the same URL gate. CI must supply the URL for every such test; a green run with missing URLs gives no PostgreSQL evidence.
241
243
 
242
- #### Inherited tags
243
-
244
- A root Vitest config that gathers inline projects from package configs uses `inheritTags(projects, root)` to copy the tags of each extended config into its project:
245
-
246
- ```ts
247
- import { inheritTags } from "@shivaedev/quality/vitest.ts";
248
- import { defineConfig } from "vitest/config";
249
-
250
- const bakery = { extends: "./packages/bakery/vitest.config.ts", root: "./packages/bakery", test: { name: "bakery" } };
251
-
252
- export default defineConfig(async () => ({
253
- test: { projects: await inheritTags([bakery], import.meta.dirname) },
254
- }));
255
- ```
256
-
257
- Vitest otherwise drops tags from an inline project's extended config. A project's own tag wins over an inherited tag with the same name; `extends: true`, globs and file-path projects stay unchanged. The [tooling guide](https://github.com/ShivaeDev/platform/blob/main/packages/quality/docs/tooling.md#inherited-tags) gives the config-loading limits.
258
-
259
244
  #### Configuration limits
260
245
 
261
246
  All built-in and local rules run at `error`. Config settings cannot disable a rule or downgrade it to a warning. Record existing debt in the baseline instead. Source and test line limits can only be lowered from 150 and 300, and the comment limit from 2; custom test-file patterns and inventory exclusions are rejected.
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect";
2
- import { ChildProcessSpawner } from "effect/unstable/process";
2
+ import { ChildProcessSpawner } from "effect/process";
3
3
  import { SetupFailure } from "#failure.ts";
4
4
  export interface GitResult {
5
5
  readonly code: number;
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/git/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,GAAG,GAAG,mBAAmB,CAAC,mBAAmB,CAAC;AAE1D,eAAO,MAAM,GAAG,QAAS,MAAM,QAAQ,SAAS,MAAM,EAAE,KAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,CAWC,CAAC;AAEvG,eAAO,MAAM,SAAS,QAAS,MAAM,QAAQ,SAAS,MAAM,EAAE,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,CAKtG,CAAC"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/git/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,GAAG,GAAG,mBAAmB,CAAC,mBAAmB,CAAC;AAE1D,eAAO,MAAM,GAAG,QAAS,MAAM,QAAQ,SAAS,MAAM,EAAE,KAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,CAWC,CAAC;AAEvG,eAAO,MAAM,SAAS,QAAS,MAAM,QAAQ,SAAS,MAAM,EAAE,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,CAKtG,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { Effect, Stream } from "effect";
2
- import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
2
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
3
3
  import { SetupFailure } from "#failure.ts";
4
4
  export const git = (cwd, args) => Effect.scoped(Effect.gen(function* () {
5
5
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
@@ -1 +1 @@
1
- {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/git/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAU3C,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,IAAuB,EAA+C,EAAE,CACxG,MAAM,CAAC,MAAM,CACZ,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,mBAAmB,CAAC;IAC/D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAClG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAC/C,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,EACpH,EAAE,WAAW,EAAE,WAAW,EAAE,CAC5B,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC,CAAC,CACF,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,mBAAmB,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AAEvG,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,IAAuB,EAA4C,EAAE,CAC3G,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CACzC,MAAM,CAAC,IAAI,KAAK,CAAC;IAChB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;IAC/B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,aAAa,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAC7H,CAAC"}
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/git/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAU3C,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,IAAuB,EAA+C,EAAE,CACxG,MAAM,CAAC,MAAM,CACZ,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,mBAAmB,CAAC;IAC/D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAClG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAC/C,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,EACpH,EAAE,WAAW,EAAE,WAAW,EAAE,CAC5B,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC,CAAC,CACF,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,mBAAmB,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AAEvG,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,IAAuB,EAA4C,EAAE,CAC3G,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CACzC,MAAM,CAAC,IAAI,KAAK,CAAC;IAChB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;IAC/B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,aAAa,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAC7H,CAAC"}
@@ -7,5 +7,5 @@ export interface HookInstall {
7
7
  readonly force: boolean;
8
8
  readonly launch: Launch;
9
9
  }
10
- export declare const installHook: (install: HookInstall) => Effect.Effect<void, SetupFailure, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | FileSystem.FileSystem>;
10
+ export declare const installHook: (install: HookInstall) => Effect.Effect<void, SetupFailure, import("effect/process/ChildProcessSpawner").ChildProcessSpawner | FileSystem.FileSystem>;
11
11
  //# sourceMappingURL=install.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/hooks/install.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAA6B,KAAK,MAAM,EAAc,MAAM,cAAc,CAAC;AAIlF,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AA4BD,eAAO,MAAM,WAAW,gKAyBtB,CAAC"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/hooks/install.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAA6B,KAAK,MAAM,EAAc,MAAM,cAAc,CAAC;AAIlF,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AA4BD,eAAO,MAAM,WAAW,uJAyBtB,CAAC"}
@@ -5,5 +5,5 @@ export interface HookLocation {
5
5
  readonly hooksPath: string | undefined;
6
6
  readonly toplevel: string;
7
7
  }
8
- export declare const hookLocation: (cwd: string) => Effect.Effect<HookLocation, SetupFailure, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
8
+ export declare const hookLocation: (cwd: string) => Effect.Effect<HookLocation, SetupFailure, import("effect/process/ChildProcessSpawner").ChildProcessSpawner>;
9
9
  //# sourceMappingURL=location.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../src/hooks/location.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAGD,eAAO,MAAM,YAAY,uIAevB,CAAC"}
1
+ {"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../src/hooks/location.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAGD,eAAO,MAAM,YAAY,8HAevB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect";
2
- import { ChildProcessSpawner } from "effect/unstable/process";
2
+ import { ChildProcessSpawner } from "effect/process";
3
3
  import { GateFailed, SetupFailure } from "#failure.ts";
4
4
  export declare const preCommitHook: (cwd: string, path: string | undefined) => Effect.Effect<undefined, GateFailed | SetupFailure, ChildProcessSpawner.ChildProcessSpawner | import("effect/FileSystem").FileSystem>;
5
5
  //# sourceMappingURL=preCommit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preCommit.d.ts","sourceRoot":"","sources":["../../src/hooks/preCommit.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,MAAM,EAAU,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI5E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAyCvD,eAAO,MAAM,aAAa,kLAoBxB,CAAC"}
1
+ {"version":3,"file":"preCommit.d.ts","sourceRoot":"","sources":["../../src/hooks/preCommit.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,MAAM,EAAU,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAInE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAyCvD,eAAO,MAAM,aAAa,kLAoBxB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { Console, Effect, Schema } from "effect";
3
- import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
3
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
4
4
  import { lint } from "#cli/lint.ts";
5
5
  import { loadConfig } from "#config/load.ts";
6
6
  import { decodeWith, validOrFail } from "#decoded.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"preCommit.js","sourceRoot":"","sources":["../../src/hooks/preCommit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"preCommit.js","sourceRoot":"","sources":["../../src/hooks/preCommit.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import { Effect, FileSystem } from "effect";
2
2
  import { SetupFailure } from "#failure.ts";
3
- export declare const uninstallHook: (cwd: string) => Effect.Effect<void, SetupFailure, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | FileSystem.FileSystem>;
3
+ export declare const uninstallHook: (cwd: string) => Effect.Effect<void, SetupFailure, import("effect/process/ChildProcessSpawner").ChildProcessSpawner | FileSystem.FileSystem>;
4
4
  //# sourceMappingURL=uninstall.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../../src/hooks/uninstall.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,eAAO,MAAM,aAAa,uJAYxB,CAAC"}
1
+ {"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../../src/hooks/uninstall.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,eAAO,MAAM,aAAa,8IAYxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function isTooling(directory: string, path: string): boolean;
2
+ //# sourceMappingURL=isTooling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isTooling.d.ts","sourceRoot":"","sources":["../../src/imports/isTooling.ts"],"names":[],"mappings":"AAMA,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAIlE"}
@@ -0,0 +1,9 @@
1
+ import { posix } from "node:path";
2
+ const TOOL_FOLDERS = new Set(["script", "scripts", "tooling"]);
3
+ const CONFIG_FILE = /(?:^|\.)config\.[cm]?[jt]sx?$/u;
4
+ export function isTooling(directory, path) {
5
+ const local = posix.relative(directory, path);
6
+ const [folder = ""] = local.split("/");
7
+ return TOOL_FOLDERS.has(folder) || (!local.includes("/") && CONFIG_FILE.test(local));
8
+ }
9
+ //# sourceMappingURL=isTooling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isTooling.js","sourceRoot":"","sources":["../../src/imports/isTooling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/D,MAAM,WAAW,GAAG,gCAAgC,CAAC;AAErD,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,IAAY;IACxD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,OAAO,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACtF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/imports/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAarD,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,CAkB1H"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/imports/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAkCrD,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,CAsB1H"}
@@ -1,6 +1,27 @@
1
- import { statSync } from "node:fs";
1
+ import { readFileSync, statSync } from "node:fs";
2
2
  import { join, posix } from "node:path";
3
+ import { isTooling } from "./isTooling.js";
3
4
  import { packageOf } from "./workspace.js";
5
+ function executablePath(value) {
6
+ return typeof value === "string" && value.trim().length > 0;
7
+ }
8
+ function hasExecutable(root, directory) {
9
+ const path = join(root, directory, "package.json");
10
+ try {
11
+ const manifest = JSON.parse(readFileSync(path, "utf8"));
12
+ if (typeof manifest !== "object" || manifest === null || Array.isArray(manifest)) {
13
+ throw new Error("the manifest must be an object");
14
+ }
15
+ const bin = Reflect.get(manifest, "bin");
16
+ return executablePath(bin) || (typeof bin === "object" && bin !== null && !Array.isArray(bin) && Object.values(bin).some(executablePath));
17
+ }
18
+ catch (cause) {
19
+ if (cause instanceof Error && "code" in cause && cause.code === "ENOENT") {
20
+ return false;
21
+ }
22
+ throw new Error(`cannot read runtime policy at ${path}`, { cause });
23
+ }
24
+ }
4
25
  function directoryExists(path) {
5
26
  try {
6
27
  return statSync(path).isDirectory();
@@ -17,10 +38,14 @@ export function runtimeOf(inputs, packages) {
17
38
  const adopted = new Set(owners
18
39
  .filter((owner) => ["client", "server"].some((folder) => directoryExists(join(inputs.root, owner.directory, "src", folder))))
19
40
  .map((owner) => owner.directory));
41
+ const executable = new Set(owners.filter((owner) => hasExecutable(inputs.root, owner.directory)).map((owner) => owner.directory));
20
42
  return (path) => {
21
43
  const owner = packageOf(packages, path)?.directory ?? ".";
44
+ if (isTooling(owner, path)) {
45
+ return "server";
46
+ }
22
47
  if (!adopted.has(owner)) {
23
- return undefined;
48
+ return executable.has(owner) ? "server" : undefined;
24
49
  }
25
50
  const local = posix.relative(owner, path);
26
51
  if (local.startsWith("src/client/")) {
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/imports/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,SAAS,EAAyB,MAAM,gBAAgB,CAAC;AAIlE,SAAS,eAAe,CAAC,IAAY;IACpC,IAAI,CAAC;QACJ,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;YACxG,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACb,CAAC;AACF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAkB,EAAE,QAAqC;IAClF,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,GAAG,CACtB,MAAM;SACJ,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;SAC5H,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CACjC,CAAC;IACF,OAAO,CAAC,IAAI,EAAE,EAAE;QACf,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,SAAS,IAAI,GAAG,CAAC;QAC1D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1C,IAAI,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACrC,OAAO,QAAQ,CAAC;QACjB,CAAC;QACD,OAAO,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9D,CAAC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/imports/runtime.ts"],"names":[],"mappings":"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"}
@@ -21,7 +21,7 @@ export declare const builtInRules: readonly [import("../rule.ts").Rule<"structur
21
21
  }>, import("../rule.ts").Rule<"files/folder-names", {
22
22
  readonly content?: readonly string[];
23
23
  readonly toolOwned?: readonly string[];
24
- }>, import("../rule.ts").Rule<"files/other-names", {
24
+ }>, import("../rule.ts").Rule<"files/distinct-case", undefined>, import("../rule.ts").Rule<"files/other-names", {
25
25
  readonly content?: readonly string[];
26
26
  readonly toolOwned?: readonly string[];
27
27
  }>, import("../rule.ts").Rule<"tests/follow", {
@@ -1 +1 @@
1
- {"version":3,"file":"built-in.d.ts","sourceRoot":"","sources":["../../src/rules/built-in.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DA6Bf,CAAC"}
1
+ {"version":3,"file":"built-in.d.ts","sourceRoot":"","sources":["../../src/rules/built-in.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DA8Bf,CAAC"}
@@ -5,6 +5,7 @@ import { noJsdoc } from "#rules/comments/no-jsdoc.ts";
5
5
  import { noLineReference } from "#rules/comments/no-line-reference.ts";
6
6
  import { noPrReference } from "#rules/comments/no-pr-reference.ts";
7
7
  import { noTodo } from "#rules/comments/no-todo.ts";
8
+ import { distinctCase } from "#rules/files/distinctCase.ts";
8
9
  import { folderNames } from "#rules/files/folderNames.ts";
9
10
  import { namedAfterExport } from "#rules/files/namedAfterExport.ts";
10
11
  import { otherNames } from "#rules/files/otherNames.ts";
@@ -51,6 +52,7 @@ export const builtInRules = [
51
52
  manifestsSorted,
52
53
  namedAfterExport,
53
54
  folderNames,
55
+ distinctCase,
54
56
  otherNames,
55
57
  testsFollow,
56
58
  testsColocated,
@@ -1 +1 @@
1
- {"version":3,"file":"built-in.js","sourceRoot":"","sources":["../../src/rules/built-in.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,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,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,CAAC,MAAM,YAAY,GAAG;IAC3B,QAAQ;IACR,OAAO;IACP,eAAe;IACf,aAAa;IACb,QAAQ;IACR,MAAM;IACN,mBAAmB;IACnB,UAAU;IACV,QAAQ;IACR,YAAY;IACZ,oBAAoB;IACpB,cAAc;IACd,gBAAgB;IAChB,KAAK;IACL,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,cAAc;IACd,UAAU;IACV,eAAe;IACf,gBAAgB;IAChB,WAAW;IACX,UAAU;IACV,WAAW;IACX,cAAc;IACd,UAAU;CACD,CAAC"}
1
+ {"version":3,"file":"built-in.js","sourceRoot":"","sources":["../../src/rules/built-in.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,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,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,CAAC,MAAM,YAAY,GAAG;IAC3B,QAAQ;IACR,OAAO;IACP,eAAe;IACf,aAAa;IACb,QAAQ;IACR,MAAM;IACN,mBAAmB;IACnB,UAAU;IACV,QAAQ;IACR,YAAY;IACZ,oBAAoB;IACpB,cAAc;IACd,gBAAgB;IAChB,KAAK;IACL,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,cAAc;IACd,UAAU;IACV,eAAe;IACf,gBAAgB;IAChB,WAAW;IACX,YAAY;IACZ,UAAU;IACV,WAAW;IACX,cAAc;IACd,UAAU;CACD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { definePatternRule } from "./pattern-rule.js";
2
2
  export const noEnvironmentPragma = definePatternRule({
3
- description: "A test file gets its environment from its name, not from a pragma: `*.dom.test.ts` runs in a DOM, every other test in Node. `@shivaedev/quality/vitest.ts` sets up the Vitest projects that read the name.",
3
+ description: "A test file gets its environment from its name, not from a pragma: `*.dom.test.ts` runs in a DOM, every other test in Node. `@shivaedev/quality/testProjects.ts` sets up the Vitest projects that read the name.",
4
4
  id: "comments/no-environment-pragma",
5
5
  message: (match) => `Sets the test environment with "${match}". Name the file *.dom.test.ts or *.dom.test.tsx instead.`,
6
6
  patterns: [/^@(?:vitest|jest)-environment(?:-options)?(?=\s|$)/mu],
@@ -1 +1 @@
1
- {"version":3,"file":"no-environment-pragma.js","sourceRoot":"","sources":["../../../src/rules/comments/no-environment-pragma.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;IACpD,WAAW,EACV,4MAA4M;IAC7M,EAAE,EAAE,gCAAgC;IACpC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,mCAAmC,KAAK,2DAA2D;IACvH,QAAQ,EAAE,CAAC,sDAAsD,CAAC;CAClE,CAAC,CAAC"}
1
+ {"version":3,"file":"no-environment-pragma.js","sourceRoot":"","sources":["../../../src/rules/comments/no-environment-pragma.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;IACpD,WAAW,EACV,kNAAkN;IACnN,EAAE,EAAE,gCAAgC;IACpC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,mCAAmC,KAAK,2DAA2D;IACvH,QAAQ,EAAE,CAAC,sDAAsD,CAAC;CAClE,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const distinctCase: import("#rule.ts").Rule<"files/distinct-case", undefined>;
2
+ //# sourceMappingURL=distinctCase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distinctCase.d.ts","sourceRoot":"","sources":["../../../src/rules/files/distinctCase.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,YAAY,2DAmBvB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { posix } from "node:path";
2
+ import { defineRule } from "#rule.ts";
3
+ const CODE = /\.(?<mode>[cm]?)[jt]sx?$/u;
4
+ function sourcesByPath(files) {
5
+ const sources = new Map();
6
+ function add(path, source) {
7
+ const known = sources.get(path) ?? [];
8
+ sources.set(path, known.includes(source) ? known : [...known, source]);
9
+ }
10
+ for (const file of files) {
11
+ add(file.replace(CODE, ".$<mode>js"), file);
12
+ for (let folder = posix.dirname(file); folder !== "."; folder = posix.dirname(folder)) {
13
+ add(folder, folder);
14
+ }
15
+ }
16
+ return sources;
17
+ }
18
+ function collisionsOf(paths) {
19
+ const groups = new Map();
20
+ for (const path of paths) {
21
+ const key = path.toLowerCase();
22
+ groups.set(key, [...(groups.get(key) ?? []), path]);
23
+ }
24
+ return new Map([...groups].filter(([, group]) => group.length > 1));
25
+ }
26
+ function message(source, others) {
27
+ const names = others.map((other) => `"${posix.basename(other)}"`).join(", ");
28
+ return `"${posix.basename(source)}" and ${names} differ only by case, in their names or in the files they build to, so they are one path on a case-insensitive filesystem such as macOS or Windows. Rename one of them.`;
29
+ }
30
+ export const distinctCase = defineRule({
31
+ check: ({ files }) => {
32
+ const sources = sourcesByPath(files);
33
+ const collisions = collisionsOf(sources.keys());
34
+ return [...collisions]
35
+ .filter(([key]) => !collisions.has(posix.dirname(key)))
36
+ .flatMap(([, group]) => {
37
+ const all = group.flatMap((path) => sources.get(path) ?? []).sort();
38
+ return all.map((source) => ({
39
+ file: source,
40
+ message: message(source, all.filter((other) => other !== source)),
41
+ }));
42
+ });
43
+ },
44
+ description: "No two paths, or the files they build to, differ only by case, so a checkout and a build work on a case-insensitive filesystem.",
45
+ id: "files/distinct-case",
46
+ });
47
+ //# sourceMappingURL=distinctCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distinctCase.js","sourceRoot":"","sources":["../../../src/rules/files/distinctCase.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/rules/imports/manifest.ts"],"names":[],"mappings":"AAgFA,eAAO,MAAM,eAAe,wDAmC1B,CAAC"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/rules/imports/manifest.ts"],"names":[],"mappings":"AAwEA,eAAO,MAAM,eAAe,wDAmC1B,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { posix } from "node:path";
2
2
  import { importGraph } from "#imports/graph.ts";
3
+ import { isTooling } from "#imports/isTooling.ts";
3
4
  import { builtinName } from "#imports/resolve.ts";
4
5
  import { packageOf } from "#imports/workspace.ts";
5
6
  import { isTestCode } from "#naming/testName.ts";
@@ -45,15 +46,8 @@ async function manifestDependencies(inputs, owner, graph) {
45
46
  throw new Error(`cannot read dependency policy at ${path}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
46
47
  }
47
48
  }
48
- const TOOL_FOLDERS = new Set(["script", "scripts", "tooling"]);
49
- const CONFIG_FILE = /(?:^|\.)config\.[cm]?[jt]sx?$/u;
50
49
  function developmentFile(owner, path) {
51
- if (isTestCode(path)) {
52
- return true;
53
- }
54
- const local = posix.relative(owner.directory, path);
55
- const [folder = ""] = local.split("/");
56
- return TOOL_FOLDERS.has(folder) || (!local.includes("/") && CONFIG_FILE.test(local));
50
+ return isTestCode(path) || isTooling(owner.directory, path);
57
51
  }
58
52
  function developmentImport(policy, owner, path, runtime) {
59
53
  if (runtime.has(path)) {
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/rules/imports/manifest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/rules/imports/manifest.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/rules/imports/runtime.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,cAAc,uDA4BzB,CAAC"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/rules/imports/runtime.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,cAAc,uDAiCzB,CAAC"}
@@ -1,4 +1,3 @@
1
- import { browserGlobals } from "#imports/browserGlobals.ts";
2
1
  import { importGraph } from "#imports/graph.ts";
3
2
  import { builtinName } from "#imports/resolve.ts";
4
3
  import { runtimeOf } from "#imports/runtime.ts";
@@ -33,9 +32,14 @@ export const importsRuntime = defineRule({
33
32
  },
34
33
  ];
35
34
  });
36
- return [...imports, ...inputs.sources.filter((file) => !isTestCode(file.path) && runtime(file.path) === "shared").flatMap(browserGlobals)];
35
+ const shared = inputs.sources.filter((file) => !isTestCode(file.path) && runtime(file.path) === "shared");
36
+ if (shared.length === 0) {
37
+ return imports;
38
+ }
39
+ const { browserGlobals } = await import("#imports/browserGlobals.ts");
40
+ return [...imports, ...shared.flatMap(browserGlobals)];
37
41
  },
38
- description: "In packages with src/client/ or src/server/, folder names define runtime boundaries. Shared code runs in either runtime without browser globals or Node built-ins.",
42
+ description: "Runtime folders define client, server and shared code. Executable packages without runtime folders and package-root tooling are server code.",
39
43
  id: "imports/runtime",
40
44
  });
41
45
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/rules/imports/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAgB,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,SAAS,eAAe,CAAC,IAAa,EAAE,EAAuB,EAAE,OAAgB;IAChF,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvB,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;IACxC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACvB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,IAAI,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjD,OAAO,EAAE,CAAC;YACX,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvE,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,SAAS,CAAC;YAC5F,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;gBACzC,OAAO,EAAE,CAAC;YACX,CAAC;YACD,OAAO;gBACN;oBACC,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,OAAO,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,iBAAiB,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,aAAa,IAAI,CAAC,SAAS,mHAAmH;oBAC1P,OAAO,EAAE,IAAI,CAAC,SAAS;iBACvB;aACD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5I,CAAC;IACD,WAAW,EACV,oKAAoK;IACrK,EAAE,EAAE,iBAAiB;CACrB,CAAC,CAAC"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/rules/imports/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAgB,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,SAAS,eAAe,CAAC,IAAa,EAAE,EAAuB,EAAE,OAAgB;IAChF,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvB,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;IACxC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACvB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,IAAI,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjD,OAAO,EAAE,CAAC;YACX,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvE,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,SAAS,CAAC;YAC5F,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;gBACzC,OAAO,EAAE,CAAC;YACX,CAAC;YACD,OAAO;gBACN;oBACC,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,OAAO,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,iBAAiB,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,aAAa,IAAI,CAAC,SAAS,mHAAmH;oBAC1P,OAAO,EAAE,IAAI,CAAC,SAAS;iBACvB;aACD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC;QAC1G,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC;QAChB,CAAC;QACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,WAAW,EACV,8IAA8I;IAC/I,EAAE,EAAE,iBAAiB;CACrB,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type TestUserConfig } from "vitest/config";
2
+ export declare function testProjects(...options: readonly never[]): TestUserConfig;
3
+ //# sourceMappingURL=testProjects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testProjects.d.ts","sourceRoot":"","sources":["../src/testProjects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAepE,wBAAgB,YAAY,CAAC,GAAG,OAAO,EAAE,SAAS,KAAK,EAAE,GAAG,cAAc,CAczE"}
@@ -0,0 +1,25 @@
1
+ import { defaultExclude } from "vitest/config";
2
+ const EXTENSION = "?(c|m)[jt]s?(x)";
3
+ const TYPECHECK_ALONE = `**/typecheck.test.${EXTENSION}`;
4
+ function named(environment) {
5
+ return environment === undefined ? `**/*.@(test|spec).${EXTENSION}` : `**/*.${environment}.@(test|spec).${EXTENSION}`;
6
+ }
7
+ function excluding(...patterns) {
8
+ return [...defaultExclude, named("typecheck"), TYPECHECK_ALONE, ...patterns];
9
+ }
10
+ export function testProjects(...options) {
11
+ if (options.length > 0) {
12
+ throw new Error("testProjects takes no options. Remove suite exclusions; every test belongs in its named project.");
13
+ }
14
+ return {
15
+ project: ["unit", "dom"],
16
+ projects: [
17
+ { extends: true, test: { environment: "node", exclude: excluding(named("dom"), named("slow")), include: [named()], name: "unit" } },
18
+ { extends: true, test: { environment: "happy-dom", exclude: excluding(named("slow")), include: [named("dom")], name: "dom" } },
19
+ { extends: true, test: { environment: "node", exclude: excluding(), include: [named("slow")], name: "slow" } },
20
+ ],
21
+ // Tests that start real servers, browsers or CLIs need seconds on a busy CI runner, and Vitest's 5s default fails them for load, not behavior.
22
+ testTimeout: 30_000,
23
+ };
24
+ }
25
+ //# sourceMappingURL=testProjects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testProjects.js","sourceRoot":"","sources":["../src/testProjects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAuB,MAAM,eAAe,CAAC;AAGpE,MAAM,SAAS,GAAG,iBAAiB,CAAC;AAEpC,MAAM,eAAe,GAAG,qBAAqB,SAAS,EAAE,CAAC;AAEzD,SAAS,KAAK,CAAC,WAAyB;IACvC,OAAO,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,WAAW,iBAAiB,SAAS,EAAE,CAAC;AACvH,CAAC;AAED,SAAS,SAAS,CAAC,GAAG,QAA2B;IAChD,OAAO,CAAC,GAAG,cAAc,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,eAAe,EAAE,GAAG,QAAQ,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAG,OAAyB;IACxD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kGAAkG,CAAC,CAAC;IACrH,CAAC;IACD,OAAO;QACN,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;QACxB,QAAQ,EAAE;YACT,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YACnI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;YAC9H,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;SAC9G;QACD,+IAA+I;QAC/I,WAAW,EAAE,MAAM;KACnB,CAAC;AACH,CAAC"}
package/docs/modules.md CHANGED
@@ -14,7 +14,7 @@ A module link opens its source. Type and value declarations with the same name a
14
14
  | [failure.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/failure.ts) | `SetupFailure`, `GateFailed` |
15
15
  | [rule.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rule.ts) | `Finding`, `Findings`, `SourceFile`, `RuleInputs`, `RuleContext`, `Configured`, `Rule`, `defineRule` |
16
16
  | [standard-schema.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/standard-schema.ts) | `StandardSchemaV1`, `StandardResult`, `StandardIssue`, `describeIssue` |
17
- | [vitest.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/vitest.ts) | `testProjects`, `inheritTags` |
17
+ | [testProjects.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/testProjects.ts) | `testProjects` |
18
18
 
19
19
  ## baseline
20
20
 
@@ -188,6 +188,7 @@ A module link opens its source. Type and value declarations with the same name a
188
188
 
189
189
  | Module | Exported names |
190
190
  | --- | --- |
191
+ | [rules/files/distinctCase.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/files/distinctCase.ts) | `distinctCase` |
191
192
  | [rules/files/folderNames.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/files/folderNames.ts) | `folderNames` |
192
193
  | [rules/files/namedAfterExport.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/files/namedAfterExport.ts) | `namedAfterExport` |
193
194
  | [rules/files/otherNames.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/files/otherNames.ts) | `otherNames` |
package/docs/naming.md CHANGED
@@ -84,6 +84,10 @@ The `toolOwned` option lists folders a tool names, `migrations/` by default. Aut
84
84
 
85
85
  The `toolOwned` option lists files a tool names: dotfiles, `package.json`, `tsconfig*.json`, `biome.json`, `*.config.*` and `migrations/` by default.
86
86
 
87
+ ### Case
88
+
89
+ `files/distinct-case` keeps every path apart on a case-insensitive filesystem, such as macOS or Windows. Two files or folders in one folder must differ by more than case, and so must the files a build makes of them: `ReadingHistory.tsx` and `readingHistory.ts` both build to `readingHistory.js`, so they are a finding. A folder pair is one finding, not one per file inside it.
90
+
87
91
  ### Tests
88
92
 
89
93
  A test sits beside the code it covers, and its name says what it covers and where it runs.
package/docs/rules.md CHANGED
@@ -187,7 +187,9 @@ When the sources hold no module at all, the graph-building rules stop the run in
187
187
 
188
188
  #### Runtime folders
189
189
 
190
- `imports/runtime` adopts a package automatically when it has `src/client/` or `src/server/`, including folders outside `sources`. In an adopted package, code in `src/client/` is browser code, code in `src/server/` is server code, and code anywhere else is shared. A package without either folder retains its existing policies. Existing explicit fences keep running in either case.
190
+ `imports/runtime` adopts a package automatically when it has `src/client/` or `src/server/`, including folders outside `sources`. In an adopted package, code in `src/client/` is browser code, code in `src/server/` is server code, and code anywhere else is shared except package-root tooling. A package with a nonempty `bin` entry and no runtime folders is server code throughout; runtime folders take precedence over `bin`. A Node library without a CLI uses `src/server/`. `engines.node` alone does not identify Node-only code. Other packages retain their existing source policies. Existing explicit fences keep running in either case.
191
+
192
+ Package-root tooling is server code in every package, including the workspace root: top-level `script/`, `scripts/` and `tooling/` folders and top-level JavaScript or TypeScript config files. A tooling folder or config file nested under `src/` follows the source runtime policy.
191
193
 
192
194
  Client code may not import server code or Node built-ins. Shared code may import neither client nor server code and may neither import Node built-ins nor use browser globals. Client and server code may import shared code. The rule uses the resolved import graph, including type imports, re-exports, dynamic imports and literal `require()` calls; missing file targets still carry their runtime folder. Test files and `test-support/` are outside the shipped runtime policy.
193
195
 
package/docs/tooling.md CHANGED
@@ -44,10 +44,10 @@ The `biome` rule runs `biome check` with the repository's config and reports eac
44
44
 
45
45
  ## Vitest projects
46
46
 
47
- `@shivaedev/quality/vitest.ts` sets up the tests of a package by file name, so no test file sets its environment with a pragma. It needs `vitest`, and `happy-dom` for DOM tests. A package's `vitest.config.ts` reads:
47
+ `@shivaedev/quality/testProjects.ts` sets up the tests of a package by file name, so no test file sets its environment with a pragma. It needs `vitest`, and `happy-dom` for DOM tests. A package's `vitest.config.ts` reads:
48
48
 
49
49
  ```ts
50
- import { testProjects } from "@shivaedev/quality/vitest.ts";
50
+ import { testProjects } from "@shivaedev/quality/testProjects.ts";
51
51
  import { defineConfig } from "vitest/config";
52
52
 
53
53
  export default defineConfig({ test: testProjects() });
@@ -63,21 +63,6 @@ Type tests (`*.typecheck.test.ts`, `*.typecheck.spec.ts` and `typecheck.test.ts`
63
63
 
64
64
  `testProjects()` takes no options. Every conventionally named suite runs in its project regardless of its folder; exclusion options are rejected.
65
65
 
66
- ### Inherited tags
67
-
68
- Vitest gives an inline project only the [tags](https://vitest.dev/guide/test-tags) it declares itself, never those of a config file it `extends`. A test tagged in that file then fails with `cannot apply "<tag>" tag for this test` as soon as a root config runs it. A root config that gathers the projects of several packages, or whose projects extend a shared base config, passes them through `inheritTags`:
69
-
70
- ```ts
71
- import { inheritTags } from "@shivaedev/quality/vitest.ts";
72
- import { defineConfig } from "vitest/config";
73
-
74
- const bakery = { extends: "./packages/bakery/vitest.config.ts", root: "./packages/bakery", test: { name: "bakery" } };
75
-
76
- export default defineConfig(async () => ({ test: { projects: await inheritTags([bakery], import.meta.dirname) } }));
77
- ```
78
-
79
- `inheritTags(projects, root)` loads the config file of each inline project whose `extends` is a path, resolved against `root`, and adds the tags that file declares to the project's own, so `vitest run --tags-filter=<tag>` works across the workspace. A tag the project declares itself wins over an inherited one of the same name. Config objects and config functions are supported. A project that extends `true`, and a glob or file path, comes back unchanged. The extended files load with Node's own `import`, so each must be a module Node runs without a bundler.
80
-
81
66
  ## tsconfig presets
82
67
 
83
68
  Two presets supply a shared strict TypeScript setup for type-checking and package builds.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/quality",
3
- "version": "0.19.0",
3
+ "version": "0.21.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": {
@@ -33,6 +33,7 @@
33
33
  "./tsconfig/base.json": "./tsconfig/base.json",
34
34
  "./tsconfig/package.json": "./tsconfig/package.json",
35
35
  "./package.json": "./package.json",
36
+ "./imports/isTooling.ts": null,
36
37
  "./rules/imports/bundleInputs.ts": null
37
38
  },
38
39
  "bin": {
@@ -52,25 +53,25 @@
52
53
  ],
53
54
  "dependencies": {
54
55
  "@biomejs/biome": "2.5.15",
55
- "@shivaedev/types": "0.2.0",
56
+ "@shivaedev/types": "0.2.1",
56
57
  "ignore": "7.0.12",
57
58
  "sort-package-json": "4.0.0",
58
59
  "typescript": "npm:@typescript/typescript6@6.0.2"
59
60
  },
60
61
  "devDependencies": {
61
- "@effect/platform-node": "4.0.0-rc.112",
62
- "@effect/platform-node-shared": "4.0.0-rc.112",
63
- "@effect/vitest": "4.0.0-rc.112",
62
+ "@effect/platform-node": "4.0.4",
63
+ "@effect/platform-node-shared": "4.0.4",
64
+ "@effect/vitest": "4.0.4",
64
65
  "@types/node": "24.19.1",
65
66
  "@typescript/native": "npm:typescript@7.0.2",
66
- "effect": "4.0.0-rc.112",
67
- "vitest": "4.1.11"
67
+ "effect": "4.0.4",
68
+ "vitest": "5.0.3"
68
69
  },
69
70
  "peerDependencies": {
70
- "@effect/platform-node": "4.0.0-rc.112",
71
- "@effect/platform-node-shared": "4.0.0-rc.112",
72
- "effect": "4.0.0-rc.112",
73
- "vitest": "4.1.11"
71
+ "@effect/platform-node": "4.0.4",
72
+ "@effect/platform-node-shared": "4.0.4",
73
+ "effect": "4.0.4",
74
+ "vitest": "5.0.3"
74
75
  },
75
76
  "peerDependenciesMeta": {
76
77
  "vitest": {
@@ -1,5 +1,5 @@
1
1
  import { Effect, Stream } from "effect";
2
- import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
2
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
3
3
  import { SetupFailure } from "#failure.ts";
4
4
 
5
5
  export interface GitResult {
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { Console, Effect, Schema } from "effect";
3
- import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
3
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
4
4
  import { lint } from "#cli/lint.ts";
5
5
  import { loadConfig } from "#config/load.ts";
6
6
  import { decodeWith, validOrFail } from "#decoded.ts";
@@ -0,0 +1,11 @@
1
+ import { posix } from "node:path";
2
+
3
+ const TOOL_FOLDERS = new Set(["script", "scripts", "tooling"]);
4
+
5
+ const CONFIG_FILE = /(?:^|\.)config\.[cm]?[jt]sx?$/u;
6
+
7
+ export function isTooling(directory: string, path: string): boolean {
8
+ const local = posix.relative(directory, path);
9
+ const [folder = ""] = local.split("/");
10
+ return TOOL_FOLDERS.has(folder) || (!local.includes("/") && CONFIG_FILE.test(local));
11
+ }
@@ -1,10 +1,32 @@
1
- import { statSync } from "node:fs";
1
+ import { readFileSync, statSync } from "node:fs";
2
2
  import { join, posix } from "node:path";
3
3
  import type { RuleInputs } from "#rule.ts";
4
+ import { isTooling } from "./isTooling.ts";
4
5
  import { packageOf, type WorkspacePackage } from "./workspace.ts";
5
6
 
6
7
  export type Runtime = "client" | "server" | "shared";
7
8
 
9
+ function executablePath(value: unknown): boolean {
10
+ return typeof value === "string" && value.trim().length > 0;
11
+ }
12
+
13
+ function hasExecutable(root: string, directory: string): boolean {
14
+ const path = join(root, directory, "package.json");
15
+ try {
16
+ const manifest: unknown = JSON.parse(readFileSync(path, "utf8"));
17
+ if (typeof manifest !== "object" || manifest === null || Array.isArray(manifest)) {
18
+ throw new Error("the manifest must be an object");
19
+ }
20
+ const bin: unknown = Reflect.get(manifest, "bin");
21
+ return executablePath(bin) || (typeof bin === "object" && bin !== null && !Array.isArray(bin) && Object.values(bin).some(executablePath));
22
+ } catch (cause) {
23
+ if (cause instanceof Error && "code" in cause && cause.code === "ENOENT") {
24
+ return false;
25
+ }
26
+ throw new Error(`cannot read runtime policy at ${path}`, { cause });
27
+ }
28
+ }
29
+
8
30
  function directoryExists(path: string): boolean {
9
31
  try {
10
32
  return statSync(path).isDirectory();
@@ -23,10 +45,14 @@ export function runtimeOf(inputs: RuleInputs, packages: readonly WorkspacePackag
23
45
  .filter((owner) => ["client", "server"].some((folder) => directoryExists(join(inputs.root, owner.directory, "src", folder))))
24
46
  .map((owner) => owner.directory),
25
47
  );
48
+ const executable = new Set(owners.filter((owner) => hasExecutable(inputs.root, owner.directory)).map((owner) => owner.directory));
26
49
  return (path) => {
27
50
  const owner = packageOf(packages, path)?.directory ?? ".";
51
+ if (isTooling(owner, path)) {
52
+ return "server";
53
+ }
28
54
  if (!adopted.has(owner)) {
29
- return undefined;
55
+ return executable.has(owner) ? "server" : undefined;
30
56
  }
31
57
  const local = posix.relative(owner, path);
32
58
  if (local.startsWith("src/client/")) {
@@ -5,6 +5,7 @@ import { noJsdoc } from "#rules/comments/no-jsdoc.ts";
5
5
  import { noLineReference } from "#rules/comments/no-line-reference.ts";
6
6
  import { noPrReference } from "#rules/comments/no-pr-reference.ts";
7
7
  import { noTodo } from "#rules/comments/no-todo.ts";
8
+ import { distinctCase } from "#rules/files/distinctCase.ts";
8
9
  import { folderNames } from "#rules/files/folderNames.ts";
9
10
  import { namedAfterExport } from "#rules/files/namedAfterExport.ts";
10
11
  import { otherNames } from "#rules/files/otherNames.ts";
@@ -52,6 +53,7 @@ export const builtInRules = [
52
53
  manifestsSorted,
53
54
  namedAfterExport,
54
55
  folderNames,
56
+ distinctCase,
55
57
  otherNames,
56
58
  testsFollow,
57
59
  testsColocated,
@@ -2,7 +2,7 @@ import { definePatternRule } from "./pattern-rule.ts";
2
2
 
3
3
  export const noEnvironmentPragma = definePatternRule({
4
4
  description:
5
- "A test file gets its environment from its name, not from a pragma: `*.dom.test.ts` runs in a DOM, every other test in Node. `@shivaedev/quality/vitest.ts` sets up the Vitest projects that read the name.",
5
+ "A test file gets its environment from its name, not from a pragma: `*.dom.test.ts` runs in a DOM, every other test in Node. `@shivaedev/quality/testProjects.ts` sets up the Vitest projects that read the name.",
6
6
  id: "comments/no-environment-pragma",
7
7
  message: (match) => `Sets the test environment with "${match}". Name the file *.dom.test.ts or *.dom.test.tsx instead.`,
8
8
  patterns: [/^@(?:vitest|jest)-environment(?:-options)?(?=\s|$)/mu],
@@ -0,0 +1,54 @@
1
+ import { posix } from "node:path";
2
+ import { defineRule, type Finding } from "#rule.ts";
3
+
4
+ const CODE = /\.(?<mode>[cm]?)[jt]sx?$/u;
5
+
6
+ function sourcesByPath(files: readonly string[]): ReadonlyMap<string, readonly string[]> {
7
+ const sources = new Map<string, readonly string[]>();
8
+ function add(path: string, source: string) {
9
+ const known = sources.get(path) ?? [];
10
+ sources.set(path, known.includes(source) ? known : [...known, source]);
11
+ }
12
+ for (const file of files) {
13
+ add(file.replace(CODE, ".$<mode>js"), file);
14
+ for (let folder = posix.dirname(file); folder !== "."; folder = posix.dirname(folder)) {
15
+ add(folder, folder);
16
+ }
17
+ }
18
+ return sources;
19
+ }
20
+
21
+ function collisionsOf(paths: Iterable<string>): ReadonlyMap<string, readonly string[]> {
22
+ const groups = new Map<string, readonly string[]>();
23
+ for (const path of paths) {
24
+ const key = path.toLowerCase();
25
+ groups.set(key, [...(groups.get(key) ?? []), path]);
26
+ }
27
+ return new Map([...groups].filter(([, group]) => group.length > 1));
28
+ }
29
+
30
+ function message(source: string, others: readonly string[]): string {
31
+ const names = others.map((other) => `"${posix.basename(other)}"`).join(", ");
32
+ return `"${posix.basename(source)}" and ${names} differ only by case, in their names or in the files they build to, so they are one path on a case-insensitive filesystem such as macOS or Windows. Rename one of them.`;
33
+ }
34
+
35
+ export const distinctCase = defineRule({
36
+ check: ({ files }) => {
37
+ const sources = sourcesByPath(files);
38
+ const collisions = collisionsOf(sources.keys());
39
+ return [...collisions]
40
+ .filter(([key]) => !collisions.has(posix.dirname(key)))
41
+ .flatMap(([, group]): readonly Finding[] => {
42
+ const all = group.flatMap((path) => sources.get(path) ?? []).sort();
43
+ return all.map((source) => ({
44
+ file: source,
45
+ message: message(
46
+ source,
47
+ all.filter((other) => other !== source),
48
+ ),
49
+ }));
50
+ });
51
+ },
52
+ description: "No two paths, or the files they build to, differ only by case, so a checkout and a build work on a case-insensitive filesystem.",
53
+ id: "files/distinct-case",
54
+ });
@@ -1,5 +1,6 @@
1
1
  import { posix } from "node:path";
2
2
  import { type ImportGraph, importGraph } from "#imports/graph.ts";
3
+ import { isTooling } from "#imports/isTooling.ts";
3
4
  import { builtinName } from "#imports/resolve.ts";
4
5
  import { packageOf, type WorkspacePackage } from "#imports/workspace.ts";
5
6
  import { isTestCode } from "#naming/testName.ts";
@@ -58,17 +59,8 @@ async function manifestDependencies(inputs: RuleInputs, owner: WorkspacePackage,
58
59
  }
59
60
  }
60
61
 
61
- const TOOL_FOLDERS = new Set(["script", "scripts", "tooling"]);
62
-
63
- const CONFIG_FILE = /(?:^|\.)config\.[cm]?[jt]sx?$/u;
64
-
65
62
  function developmentFile(owner: WorkspacePackage, path: string): boolean {
66
- if (isTestCode(path)) {
67
- return true;
68
- }
69
- const local = posix.relative(owner.directory, path);
70
- const [folder = ""] = local.split("/");
71
- return TOOL_FOLDERS.has(folder) || (!local.includes("/") && CONFIG_FILE.test(local));
63
+ return isTestCode(path) || isTooling(owner.directory, path);
72
64
  }
73
65
 
74
66
  function developmentImport(policy: ManifestDependencies | undefined, owner: WorkspacePackage, path: string, runtime: ReadonlySet<string>) {
@@ -1,4 +1,3 @@
1
- import { browserGlobals } from "#imports/browserGlobals.ts";
2
1
  import { importGraph } from "#imports/graph.ts";
3
2
  import { builtinName } from "#imports/resolve.ts";
4
3
  import { type Runtime, runtimeOf } from "#imports/runtime.ts";
@@ -35,9 +34,14 @@ export const importsRuntime = defineRule({
35
34
  },
36
35
  ];
37
36
  });
38
- return [...imports, ...inputs.sources.filter((file) => !isTestCode(file.path) && runtime(file.path) === "shared").flatMap(browserGlobals)];
37
+ const shared = inputs.sources.filter((file) => !isTestCode(file.path) && runtime(file.path) === "shared");
38
+ if (shared.length === 0) {
39
+ return imports;
40
+ }
41
+ const { browserGlobals } = await import("#imports/browserGlobals.ts");
42
+ return [...imports, ...shared.flatMap(browserGlobals)];
39
43
  },
40
44
  description:
41
- "In packages with src/client/ or src/server/, folder names define runtime boundaries. Shared code runs in either runtime without browser globals or Node built-ins.",
45
+ "Runtime folders define client, server and shared code. Executable packages without runtime folders and package-root tooling are server code.",
42
46
  id: "imports/runtime",
43
47
  });
@@ -0,0 +1,30 @@
1
+ import { defaultExclude, type TestUserConfig } from "vitest/config";
2
+ import type { Environment } from "#naming/testName.ts";
3
+
4
+ const EXTENSION = "?(c|m)[jt]s?(x)";
5
+
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(...patterns: readonly string[]): string[] {
13
+ return [...defaultExclude, named("typecheck"), TYPECHECK_ALONE, ...patterns];
14
+ }
15
+
16
+ export function testProjects(...options: readonly never[]): TestUserConfig {
17
+ if (options.length > 0) {
18
+ throw new Error("testProjects takes no options. Remove suite exclusions; every test belongs in its named project.");
19
+ }
20
+ return {
21
+ project: ["unit", "dom"],
22
+ projects: [
23
+ { extends: true, test: { environment: "node", exclude: excluding(named("dom"), named("slow")), include: [named()], name: "unit" } },
24
+ { extends: true, test: { environment: "happy-dom", exclude: excluding(named("slow")), include: [named("dom")], name: "dom" } },
25
+ { extends: true, test: { environment: "node", exclude: excluding(), include: [named("slow")], name: "slow" } },
26
+ ],
27
+ // Tests that start real servers, browsers or CLIs need seconds on a busy CI runner, and Vitest's 5s default fails them for load, not behavior.
28
+ testTimeout: 30_000,
29
+ };
30
+ }
package/dist/vitest.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { type TestProjectConfiguration, type TestUserConfig } from "vitest/config";
2
- export declare function testProjects(...options: readonly never[]): TestUserConfig;
3
- export declare function inheritTags(projects: readonly TestProjectConfiguration[], root: string): Promise<TestProjectConfiguration[]>;
4
- //# sourceMappingURL=vitest.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,wBAAwB,EAA0B,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAe3H,wBAAgB,YAAY,CAAC,GAAG,OAAO,EAAE,SAAS,KAAK,EAAE,GAAG,cAAc,CAczE;AAsBD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAW5H"}
package/dist/vitest.js DELETED
@@ -1,60 +0,0 @@
1
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
- });
6
- }
7
- return path;
8
- };
9
- import { resolve } from "node:path";
10
- import { pathToFileURL } from "node:url";
11
- import { defaultExclude } from "vitest/config";
12
- const EXTENSION = "?(c|m)[jt]s?(x)";
13
- const TYPECHECK_ALONE = `**/typecheck.test.${EXTENSION}`;
14
- function named(environment) {
15
- return environment === undefined ? `**/*.@(test|spec).${EXTENSION}` : `**/*.${environment}.@(test|spec).${EXTENSION}`;
16
- }
17
- function excluding(...patterns) {
18
- return [...defaultExclude, named("typecheck"), TYPECHECK_ALONE, ...patterns];
19
- }
20
- export function testProjects(...options) {
21
- if (options.length > 0) {
22
- throw new Error("testProjects takes no options. Remove suite exclusions; every test belongs in its named project.");
23
- }
24
- return {
25
- project: ["unit", "dom"],
26
- projects: [
27
- { extends: true, test: { environment: "node", exclude: excluding(named("dom"), named("slow")), include: [named()], name: "unit" } },
28
- { extends: true, test: { environment: "happy-dom", exclude: excluding(named("slow")), include: [named("dom")], name: "dom" } },
29
- { extends: true, test: { environment: "node", exclude: excluding(), include: [named("slow")], name: "slow" } },
30
- ],
31
- // Tests that start real servers, browsers or CLIs need seconds on a busy CI runner, and Vitest's 5s default fails them for load, not behavior.
32
- testTimeout: 30_000,
33
- };
34
- }
35
- function isConfigFunction(value) {
36
- return typeof value === "function";
37
- }
38
- function tagsOf(config) {
39
- const test = typeof config === "object" && config !== null && "test" in config ? config.test : undefined;
40
- const tags = typeof test === "object" && test !== null && "tags" in test ? test.tags : undefined;
41
- return Array.isArray(tags)
42
- ? tags.filter((tag) => typeof tag === "object" && tag !== null && typeof tag.name === "string")
43
- : [];
44
- }
45
- async function declaredTags(configFile) {
46
- const loaded = await import(__rewriteRelativeImportExtension(pathToFileURL(configFile).href));
47
- return tagsOf(isConfigFunction(loaded.default) ? await loaded.default({ command: "serve", mode: "test" }) : await loaded.default);
48
- }
49
- // Vitest reads an inline project's tags only from the project itself, never from the config file it extends.
50
- export function inheritTags(projects, root) {
51
- return Promise.all(projects.map(async (project) => {
52
- if (typeof project !== "object" || !("extends" in project) || typeof project.extends !== "string") {
53
- return project;
54
- }
55
- const own = project.test?.tags ?? [];
56
- const inherited = (await declaredTags(resolve(root, project.extends))).filter((tag) => !own.some((mine) => mine.name === tag.name));
57
- return { ...project, test: { ...project.test, tags: [...own, ...inherited] } };
58
- }));
59
- }
60
- //# sourceMappingURL=vitest.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"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"}
package/src/vitest.ts DELETED
@@ -1,65 +0,0 @@
1
- import { resolve } from "node:path";
2
- import { pathToFileURL } from "node:url";
3
- import { defaultExclude, type TestProjectConfiguration, type TestTagDefinition, type TestUserConfig } from "vitest/config";
4
- import type { Environment } from "#naming/testName.ts";
5
-
6
- const EXTENSION = "?(c|m)[jt]s?(x)";
7
-
8
- const TYPECHECK_ALONE = `**/typecheck.test.${EXTENSION}`;
9
-
10
- function named(environment?: Environment): string {
11
- return environment === undefined ? `**/*.@(test|spec).${EXTENSION}` : `**/*.${environment}.@(test|spec).${EXTENSION}`;
12
- }
13
-
14
- function excluding(...patterns: readonly string[]): string[] {
15
- return [...defaultExclude, named("typecheck"), TYPECHECK_ALONE, ...patterns];
16
- }
17
-
18
- export function testProjects(...options: readonly never[]): TestUserConfig {
19
- if (options.length > 0) {
20
- throw new Error("testProjects takes no options. Remove suite exclusions; every test belongs in its named project.");
21
- }
22
- return {
23
- project: ["unit", "dom"],
24
- projects: [
25
- { extends: true, test: { environment: "node", exclude: excluding(named("dom"), named("slow")), include: [named()], name: "unit" } },
26
- { extends: true, test: { environment: "happy-dom", exclude: excluding(named("slow")), include: [named("dom")], name: "dom" } },
27
- { extends: true, test: { environment: "node", exclude: excluding(), include: [named("slow")], name: "slow" } },
28
- ],
29
- // Tests that start real servers, browsers or CLIs need seconds on a busy CI runner, and Vitest's 5s default fails them for load, not behavior.
30
- testTimeout: 30_000,
31
- };
32
- }
33
-
34
- type ConfigFunction = (env: { readonly command: "serve"; readonly mode: "test" }) => unknown;
35
-
36
- function isConfigFunction(value: unknown): value is ConfigFunction {
37
- return typeof value === "function";
38
- }
39
-
40
- function tagsOf(config: unknown): readonly TestTagDefinition[] {
41
- const test = typeof config === "object" && config !== null && "test" in config ? config.test : undefined;
42
- const tags = typeof test === "object" && test !== null && "tags" in test ? test.tags : undefined;
43
- return Array.isArray(tags)
44
- ? tags.filter((tag): tag is TestTagDefinition => typeof tag === "object" && tag !== null && typeof tag.name === "string")
45
- : [];
46
- }
47
-
48
- async function declaredTags(configFile: string): Promise<readonly TestTagDefinition[]> {
49
- const loaded: { readonly default?: unknown } = await import(pathToFileURL(configFile).href);
50
- return tagsOf(isConfigFunction(loaded.default) ? await loaded.default({ command: "serve", mode: "test" }) : await loaded.default);
51
- }
52
-
53
- // Vitest reads an inline project's tags only from the project itself, never from the config file it extends.
54
- export function inheritTags(projects: readonly TestProjectConfiguration[], root: string): Promise<TestProjectConfiguration[]> {
55
- return Promise.all(
56
- projects.map(async (project) => {
57
- if (typeof project !== "object" || !("extends" in project) || typeof project.extends !== "string") {
58
- return project;
59
- }
60
- const own = project.test?.tags ?? [];
61
- const inherited = (await declaredTags(resolve(root, project.extends))).filter((tag) => !own.some((mine) => mine.name === tag.name));
62
- return { ...project, test: { ...project.test, tags: [...own, ...inherited] } };
63
- }),
64
- );
65
- }