@ploaness/config 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +13 -0
- package/biome-core.json +128 -0
- package/biome.json +12 -0
- package/dependency-cruiser-core.json +59 -0
- package/dependency-cruiser.json +32 -0
- package/dist/a11y.d.ts +3 -0
- package/dist/a11y.d.ts.map +1 -0
- package/dist/a11y.js +9 -0
- package/dist/a11y.js.map +1 -0
- package/dist/access.d.ts +4 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +4 -0
- package/dist/access.js.map +1 -0
- package/dist/eslint-core.d.ts +167 -0
- package/dist/eslint-core.d.ts.map +1 -0
- package/dist/eslint-core.js +698 -0
- package/dist/eslint-core.js.map +1 -0
- package/dist/eslint-library.d.ts +3 -0
- package/dist/eslint-library.d.ts.map +1 -0
- package/dist/eslint-library.js +53 -0
- package/dist/eslint-library.js.map +1 -0
- package/dist/eslint.d.ts +3 -0
- package/dist/eslint.d.ts.map +1 -0
- package/dist/eslint.js +261 -0
- package/dist/eslint.js.map +1 -0
- package/dist/playwright.d.ts +3 -0
- package/dist/playwright.d.ts.map +1 -0
- package/dist/playwright.js +108 -0
- package/dist/playwright.js.map +1 -0
- package/dist/project-settings.d.ts +3 -0
- package/dist/project-settings.d.ts.map +1 -0
- package/dist/project-settings.js +23 -0
- package/dist/project-settings.js.map +1 -0
- package/dist/vitest-core.d.ts +90 -0
- package/dist/vitest-core.d.ts.map +1 -0
- package/dist/vitest-core.js +101 -0
- package/dist/vitest-core.js.map +1 -0
- package/dist/vitest-library.d.ts +3 -0
- package/dist/vitest-library.d.ts.map +1 -0
- package/dist/vitest-library.js +37 -0
- package/dist/vitest-library.js.map +1 -0
- package/dist/vitest-setup.d.ts +2 -0
- package/dist/vitest-setup.d.ts.map +1 -0
- package/dist/vitest-setup.js +150 -0
- package/dist/vitest-setup.js.map +1 -0
- package/dist/vitest.d.ts +3 -0
- package/dist/vitest.d.ts.map +1 -0
- package/dist/vitest.js +117 -0
- package/dist/vitest.js.map +1 -0
- package/knip.json +5 -0
- package/package.json +117 -0
- package/pins.json +52 -0
- package/stylelint.json +49 -0
- package/tsconfig-core.json +34 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sequence block both Vitest configs declare, named so each carries the same shape rather than a
|
|
3
|
+
* structural type inferred separately at two call sites.
|
|
4
|
+
*/
|
|
5
|
+
export interface DeterministicSequence {
|
|
6
|
+
readonly shuffle: {
|
|
7
|
+
readonly files: boolean;
|
|
8
|
+
readonly tests: boolean;
|
|
9
|
+
};
|
|
10
|
+
readonly seed: number;
|
|
11
|
+
readonly concurrent: boolean;
|
|
12
|
+
readonly hooks: 'stack';
|
|
13
|
+
readonly setupFiles: 'list';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The per-file coverage floor every governed member is held to.
|
|
17
|
+
*
|
|
18
|
+
* Declared here because two runner configurations now read it, and a floor written twice is a floor
|
|
19
|
+
* that will eventually differ between the members of one repository.
|
|
20
|
+
*/
|
|
21
|
+
export declare const COVERAGE_THRESHOLD: number;
|
|
22
|
+
/**
|
|
23
|
+
* The fixed fast-check seed the property specs are written against.
|
|
24
|
+
*
|
|
25
|
+
* It carries no meaning. What matters is that it never changes, so a failing property is reproducible by
|
|
26
|
+
* rerunning rather than by guessing which inputs the last run happened to draw.
|
|
27
|
+
*/
|
|
28
|
+
export declare const PROPERTY_TEST_SEED: number;
|
|
29
|
+
/**
|
|
30
|
+
* The absolute path of the setup file that installs the harness guards.
|
|
31
|
+
*
|
|
32
|
+
* Absolute rather than a bare specifier: under pnpm's strict layout a consuming project cannot resolve
|
|
33
|
+
* `@ploaness/config` at all, but this module knows where it itself lives.
|
|
34
|
+
* @returns the path, for a Vitest `setupFiles` entry.
|
|
35
|
+
*/
|
|
36
|
+
export declare const harnessSetupFile: () => string;
|
|
37
|
+
/**
|
|
38
|
+
* The project's own setup file, listed only when the project wrote one.
|
|
39
|
+
*
|
|
40
|
+
* It was listed unconditionally, and nothing wrote it: `ploaness init` scaffolds five stubs and this was
|
|
41
|
+
* not among them, so a freshly initialised project met a Vite resolve error out of the `tests` gate
|
|
42
|
+
* rather than a finding. Whether a project registers matchers of its own is the project's business, so
|
|
43
|
+
* the entry is a fact ploaness reads rather than a file ploaness demands.
|
|
44
|
+
* @returns a one-entry list, or an empty one.
|
|
45
|
+
*/
|
|
46
|
+
export declare const projectSetupFiles: () => readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* How the suite is ordered, which is the check for the rule that a test reaches its verdict whatever
|
|
49
|
+
* order the suite runs in. A test that only passes in declaration order is passing on an accident of
|
|
50
|
+
* file layout, and shuffling is what turns that accident into a finding.
|
|
51
|
+
*/
|
|
52
|
+
export declare const DETERMINISTIC_SEQUENCE: DeterministicSequence;
|
|
53
|
+
/**
|
|
54
|
+
* One entry of a reporter list, spelled as the literals Vitest's own option type accepts.
|
|
55
|
+
*
|
|
56
|
+
* That type takes a reporter NAME or a `[name, options]` tuple, both as literal types - a widened
|
|
57
|
+
* `string` satisfies neither, so a list inferred from an array literal would not be assignable at
|
|
58
|
+
* either call site. Naming the shape once is what lets both configs read the same value.
|
|
59
|
+
*/
|
|
60
|
+
export type ReporterEntry = 'default' | ['github-actions', {
|
|
61
|
+
jobSummary: {
|
|
62
|
+
enabled: false;
|
|
63
|
+
};
|
|
64
|
+
}];
|
|
65
|
+
/**
|
|
66
|
+
* The reporters a run inside GitHub Actions declares.
|
|
67
|
+
*
|
|
68
|
+
* Vitest appends its own `github-actions` reporter whenever `GITHUB_ACTIONS` is set AND no reporter is
|
|
69
|
+
* declared, and that reporter writes a "Vitest Test Report" scoreboard into the workflow's job summary.
|
|
70
|
+
* A verification is a sequence of suites, several of which are MEANT to fail - `it/` drives a fixture
|
|
71
|
+
* whose network guard has to block a remote connection, and asserts that it did - so the summary
|
|
72
|
+
* reported failures at the top of a green run, with nothing beside them to say they were the expected
|
|
73
|
+
* ones. The verdict is the run's exit status; a second scoreboard that contradicts it teaches a reader
|
|
74
|
+
* to trust neither.
|
|
75
|
+
*
|
|
76
|
+
* Only the summary goes. `displayAnnotations` is left at its default, which marks a failing test on the
|
|
77
|
+
* line that failed rather than on the run's front page - and is the half of this reporter that says
|
|
78
|
+
* something the exit status does not.
|
|
79
|
+
*/
|
|
80
|
+
export declare const GITHUB_ACTIONS_REPORTERS: readonly ReporterEntry[];
|
|
81
|
+
/**
|
|
82
|
+
* The reporters both Vitest configs declare.
|
|
83
|
+
*
|
|
84
|
+
* The branch mirrors the condition Vitest itself applies rather than declaring the reporter
|
|
85
|
+
* unconditionally: outside a workflow there is no job summary and no annotation surface, so the
|
|
86
|
+
* `::error` lines would land in a local terminal as noise nothing reads.
|
|
87
|
+
* @returns the list, for a Vitest `reporters` entry.
|
|
88
|
+
*/
|
|
89
|
+
export declare const testReporters: () => readonly ReporterEntry[];
|
|
90
|
+
//# sourceMappingURL=vitest-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-core.d.ts","sourceRoot":"","sources":["../src/vitest-core.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAWD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAW,CAAA;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAsB,CAAA;AASvD;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,QAAO,MACwB,CAAA;AAE5D;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,QAAO,SAAS,MAAM,EACkC,CAAA;AAEtF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,qBAWnC,CAAA;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,CAAC,gBAAgB,EAAE;IAAE,UAAU,EAAE;QAAE,OAAO,EAAE,KAAK,CAAA;KAAE,CAAA;CAAE,CAAC,CAAA;AAE9F;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,aAAa,EAG5D,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,QAAO,SAAS,aAAa,EAC4B,CAAA"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// The Vitest values the shipped config and the ploaness repository's own config both need.
|
|
2
|
+
//
|
|
3
|
+
// The sibling of eslint-core.js, and it exists for the same reason: two configs that must agree about a
|
|
4
|
+
// literal will not stay in agreement, and the seed below is exactly the kind of literal that drifts
|
|
5
|
+
// silently because nothing fails when it does.
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { PROJECT_SETUP_FILE as PROJECT_SETUP_FILE_NAME } from '@ploaness/governance';
|
|
10
|
+
/**
|
|
11
|
+
* The setup file a project writes for itself, if it wants one, as this config must spell it.
|
|
12
|
+
*
|
|
13
|
+
* The name comes from governance rather than from a second literal here: the Biome block requires this
|
|
14
|
+
* file, the ESLint config exempts it from a rule aimed at code rather than at process configuration, and
|
|
15
|
+
* this config loads it. Three tools agreeing about one filename is a joint, not a coincidence.
|
|
16
|
+
*/
|
|
17
|
+
const PROJECT_SETUP_FILE = `./${PROJECT_SETUP_FILE_NAME}`;
|
|
18
|
+
/**
|
|
19
|
+
* The per-file coverage floor every governed member is held to.
|
|
20
|
+
*
|
|
21
|
+
* Declared here because two runner configurations now read it, and a floor written twice is a floor
|
|
22
|
+
* that will eventually differ between the members of one repository.
|
|
23
|
+
*/
|
|
24
|
+
export const COVERAGE_THRESHOLD = 80;
|
|
25
|
+
/**
|
|
26
|
+
* The fixed fast-check seed the property specs are written against.
|
|
27
|
+
*
|
|
28
|
+
* It carries no meaning. What matters is that it never changes, so a failing property is reproducible by
|
|
29
|
+
* rerunning rather than by guessing which inputs the last run happened to draw.
|
|
30
|
+
*/
|
|
31
|
+
export const PROPERTY_TEST_SEED = 1_734_000_000;
|
|
32
|
+
// The order a shuffled suite runs in. It is fixed for the same reason the seed above is: a check has one
|
|
33
|
+
// verdict on an unchanged repository, and Vitest's own default here is the wall clock, which would make
|
|
34
|
+
// the suite report differently on two runs of the same tree. One fixed seed samples one order rather
|
|
35
|
+
// than proving independence of all of them - but it is an order other than the one the files happen to
|
|
36
|
+
// be written in, which is the coupling that actually accumulates.
|
|
37
|
+
const TEST_ORDER_SEED = 1_734_000_002;
|
|
38
|
+
/**
|
|
39
|
+
* The absolute path of the setup file that installs the harness guards.
|
|
40
|
+
*
|
|
41
|
+
* Absolute rather than a bare specifier: under pnpm's strict layout a consuming project cannot resolve
|
|
42
|
+
* `@ploaness/config` at all, but this module knows where it itself lives.
|
|
43
|
+
* @returns the path, for a Vitest `setupFiles` entry.
|
|
44
|
+
*/
|
|
45
|
+
export const harnessSetupFile = () => fileURLToPath(new URL('vitest-setup.js', import.meta.url));
|
|
46
|
+
/**
|
|
47
|
+
* The project's own setup file, listed only when the project wrote one.
|
|
48
|
+
*
|
|
49
|
+
* It was listed unconditionally, and nothing wrote it: `ploaness init` scaffolds five stubs and this was
|
|
50
|
+
* not among them, so a freshly initialised project met a Vite resolve error out of the `tests` gate
|
|
51
|
+
* rather than a finding. Whether a project registers matchers of its own is the project's business, so
|
|
52
|
+
* the entry is a fact ploaness reads rather than a file ploaness demands.
|
|
53
|
+
* @returns a one-entry list, or an empty one.
|
|
54
|
+
*/
|
|
55
|
+
export const projectSetupFiles = () => existsSync(path.join(process.cwd(), PROJECT_SETUP_FILE)) ? [PROJECT_SETUP_FILE] : [];
|
|
56
|
+
/**
|
|
57
|
+
* How the suite is ordered, which is the check for the rule that a test reaches its verdict whatever
|
|
58
|
+
* order the suite runs in. A test that only passes in declaration order is passing on an accident of
|
|
59
|
+
* file layout, and shuffling is what turns that accident into a finding.
|
|
60
|
+
*/
|
|
61
|
+
export const DETERMINISTIC_SEQUENCE = Object.freeze({
|
|
62
|
+
shuffle: Object.freeze({ files: true, tests: true }),
|
|
63
|
+
seed: TEST_ORDER_SEED,
|
|
64
|
+
// A concurrent test interleaves with its neighbours, which is order-dependence rather than
|
|
65
|
+
// independence of order: it makes the coupling harder to see instead of impossible to have.
|
|
66
|
+
concurrent: false,
|
|
67
|
+
// Stated rather than inherited. A default can move between releases; a declaration cannot.
|
|
68
|
+
hooks: 'stack',
|
|
69
|
+
// The harness setup file installs the network guard, and it has to be in place before any project
|
|
70
|
+
// setup runs. Vitest's default here loads setup files in parallel, which would make that a race.
|
|
71
|
+
setupFiles: 'list',
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* The reporters a run inside GitHub Actions declares.
|
|
75
|
+
*
|
|
76
|
+
* Vitest appends its own `github-actions` reporter whenever `GITHUB_ACTIONS` is set AND no reporter is
|
|
77
|
+
* declared, and that reporter writes a "Vitest Test Report" scoreboard into the workflow's job summary.
|
|
78
|
+
* A verification is a sequence of suites, several of which are MEANT to fail - `it/` drives a fixture
|
|
79
|
+
* whose network guard has to block a remote connection, and asserts that it did - so the summary
|
|
80
|
+
* reported failures at the top of a green run, with nothing beside them to say they were the expected
|
|
81
|
+
* ones. The verdict is the run's exit status; a second scoreboard that contradicts it teaches a reader
|
|
82
|
+
* to trust neither.
|
|
83
|
+
*
|
|
84
|
+
* Only the summary goes. `displayAnnotations` is left at its default, which marks a failing test on the
|
|
85
|
+
* line that failed rather than on the run's front page - and is the half of this reporter that says
|
|
86
|
+
* something the exit status does not.
|
|
87
|
+
*/
|
|
88
|
+
export const GITHUB_ACTIONS_REPORTERS = [
|
|
89
|
+
'default',
|
|
90
|
+
['github-actions', { jobSummary: { enabled: false } }],
|
|
91
|
+
];
|
|
92
|
+
/**
|
|
93
|
+
* The reporters both Vitest configs declare.
|
|
94
|
+
*
|
|
95
|
+
* The branch mirrors the condition Vitest itself applies rather than declaring the reporter
|
|
96
|
+
* unconditionally: outside a workflow there is no job summary and no annotation surface, so the
|
|
97
|
+
* `::error` lines would land in a local terminal as noise nothing reads.
|
|
98
|
+
* @returns the list, for a Vitest `reporters` entry.
|
|
99
|
+
*/
|
|
100
|
+
export const testReporters = () => process.env['GITHUB_ACTIONS'] === 'true' ? GITHUB_ACTIONS_REPORTERS : ['default'];
|
|
101
|
+
//# sourceMappingURL=vitest-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-core.js","sourceRoot":"","sources":["../src/vitest-core.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,EAAE;AACF,wGAAwG;AACxG,oGAAoG;AACpG,+CAA+C;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,kBAAkB,IAAI,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAcpF;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAW,KAAK,uBAAuB,EAAE,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAW,EAAE,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAW,aAAa,CAAA;AAEvD,yGAAyG;AACzG,wGAAwG;AACxG,qGAAqG;AACrG,uGAAuG;AACvG,kEAAkE;AAClE,MAAM,eAAe,GAAW,aAAa,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAW,EAAE,CAC3C,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAE5D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAsB,EAAE,CACvD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AAEtF;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA0B,MAAM,CAAC,MAAM,CAAC;IACzE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACpD,IAAI,EAAE,eAAe;IACrB,2FAA2F;IAC3F,4FAA4F;IAC5F,UAAU,EAAE,KAAK;IACjB,2FAA2F;IAC3F,KAAK,EAAE,OAAO;IACd,kGAAkG;IAClG,iGAAiG;IACjG,UAAU,EAAE,MAAM;CACnB,CAAC,CAAA;AAWF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAA6B;IAChE,SAAS;IACT,CAAC,gBAAgB,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC;CACvD,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAA6B,EAAE,CAC1D,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-library.d.ts","sourceRoot":"","sources":["../src/vitest-library.ts"],"names":[],"mappings":"AAyCA,QAAA,MAAM,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAmB,CAAA;AAEjE,eAAe,MAAM,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// The Vitest configuration for a member that serves no application.
|
|
2
|
+
//
|
|
3
|
+
// Two differences from the application configuration, both about what is absent rather than about what
|
|
4
|
+
// is relaxed: the environment is node, because a package with no browser has no DOM to simulate and
|
|
5
|
+
// paying for jsdom on every file would be waste; and the React plugin is not loaded, because a package
|
|
6
|
+
// with no components has nothing for it to transform. The coverage floors, the deterministic sequence
|
|
7
|
+
// and the network guard are the same ones an application is held to.
|
|
8
|
+
import { COVERAGE_INCLUDE } from '@ploaness/governance';
|
|
9
|
+
import { defineConfig } from 'vitest/config';
|
|
10
|
+
import { projectSettings as settings } from './project-settings.js';
|
|
11
|
+
import { COVERAGE_THRESHOLD, DETERMINISTIC_SEQUENCE, harnessSetupFile, projectSetupFiles, } from './vitest-core.js';
|
|
12
|
+
const declared = defineConfig({
|
|
13
|
+
resolve: { tsconfigPaths: true },
|
|
14
|
+
test: {
|
|
15
|
+
environment: 'node',
|
|
16
|
+
include: ['tests/unit/**/*.unit.spec.ts', 'tests/int/**/*.int.spec.ts'],
|
|
17
|
+
setupFiles: [harnessSetupFile(), ...projectSetupFiles()],
|
|
18
|
+
sequence: DETERMINISTIC_SEQUENCE,
|
|
19
|
+
coverage: {
|
|
20
|
+
provider: 'v8',
|
|
21
|
+
include: [...COVERAGE_INCLUDE],
|
|
22
|
+
exclude: [...settings.coverageExclude],
|
|
23
|
+
thresholds: {
|
|
24
|
+
perFile: true,
|
|
25
|
+
lines: COVERAGE_THRESHOLD,
|
|
26
|
+
branches: COVERAGE_THRESHOLD,
|
|
27
|
+
functions: COVERAGE_THRESHOLD,
|
|
28
|
+
statements: COVERAGE_THRESHOLD,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
// Structural, for the reason the application configuration records: naming Vite's own type would make
|
|
34
|
+
// `vite` resolvable from this package a condition of type-checking a consumer's config file.
|
|
35
|
+
const config = { ...declared };
|
|
36
|
+
export default config;
|
|
37
|
+
//# sourceMappingURL=vitest-library.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-library.js","sourceRoot":"","sources":["../src/vitest-library.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,uGAAuG;AACvG,oGAAoG;AACpG,uGAAuG;AACvG,sGAAsG;AACtG,qEAAqE;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,eAAe,IAAI,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAA;AAEzB,MAAM,QAAQ,GAAoC,YAAY,CAAC;IAC7D,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;IAChC,IAAI,EAAE;QACJ,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,CAAC,8BAA8B,EAAE,4BAA4B,CAAC;QACvE,UAAU,EAAE,CAAC,gBAAgB,EAAE,EAAE,GAAG,iBAAiB,EAAE,CAAC;QACxD,QAAQ,EAAE,sBAAsB;QAChC,QAAQ,EAAE;YACR,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,CAAC,GAAG,gBAAgB,CAAC;YAC9B,OAAO,EAAE,CAAC,GAAG,QAAQ,CAAC,eAAe,CAAC;YACtC,UAAU,EAAE;gBACV,OAAO,EAAE,IAAI;gBACb,KAAK,EAAE,kBAAkB;gBACzB,QAAQ,EAAE,kBAAkB;gBAC5B,SAAS,EAAE,kBAAkB;gBAC7B,UAAU,EAAE,kBAAkB;aAC/B;SACF;KACF;CACF,CAAC,CAAA;AAEF,sGAAsG;AACtG,6FAA6F;AAC7F,MAAM,MAAM,GAAsC,EAAE,GAAG,QAAQ,EAAE,CAAA;AAEjE,eAAe,MAAM,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-setup.d.ts","sourceRoot":"","sources":["../src/vitest-setup.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// The first setup file the shipped Vitest config loads. It does two things: it reads the project
|
|
2
|
+
// environment, and it installs the network guard.
|
|
3
|
+
//
|
|
4
|
+
// It imports node builtins and @ploaness/governance, and NOTHING ELSE. A setup file that lives inside
|
|
5
|
+
// node_modules/@ploaness/config resolves `vitest`, `fast-check`, and `@testing-library/*` to the
|
|
6
|
+
// harness's own copies rather than to the project's, so a hook, a matcher, or a global seed registered
|
|
7
|
+
// against one of those would attach to a module instance the suite never loads and silently do nothing.
|
|
8
|
+
// Resolving from the project root does not rescue it either: that yields a package's CommonJS entry
|
|
9
|
+
// while the suite loads its ESM one, which is two module records again. That is why the fast-check
|
|
10
|
+
// global seed stays in the project's own `vitest.setup.ts`, and it is the constraint an otherwise
|
|
11
|
+
// reasonable refactor of this file will break.
|
|
12
|
+
//
|
|
13
|
+
// Every decision lives in @ploaness/governance. What is left here is the interception, which is the one
|
|
14
|
+
// part that cannot be pure.
|
|
15
|
+
import dns from 'node:dns';
|
|
16
|
+
import { existsSync } from 'node:fs';
|
|
17
|
+
import net from 'node:net';
|
|
18
|
+
import os from 'node:os';
|
|
19
|
+
import { describeSocketTarget, findNetworkEscape, hostOfUrl, isRecord, localAddresses, RESOLVER_METHODS, runEnvironmentFiles, } from '@ploaness/governance';
|
|
20
|
+
// A predicate rather than an assertion. `typeof value === 'function'` narrows to a shape with no call
|
|
21
|
+
// signature, so every caller would otherwise have to assert - and an assertion is uncovered by the type
|
|
22
|
+
// coverage measurement this repository holds at 100%, which is the point of preferring the predicate.
|
|
23
|
+
const isIntercepted = (value) => typeof value === 'function';
|
|
24
|
+
// Read here for the reason the Playwright config reads them: an integration spec boots the project,
|
|
25
|
+
// and a Payload configuration validates `process.env` as the module loads, so the spec dies on
|
|
26
|
+
// configuration rather than on code. A project could put this in its own `vitest.setup.ts` and many
|
|
27
|
+
// did, but then the promise that a gate running the application uses the real environment holds only
|
|
28
|
+
// for the projects that remembered. Nothing loaded here replaces a value already set, so a project
|
|
29
|
+
// that still loads them itself is unaffected, and a variable CI exported outranks both files.
|
|
30
|
+
//
|
|
31
|
+
// Vitest re-runs this module once per spec file. That costs nothing to repeat: a file that is read
|
|
32
|
+
// twice sets nothing the second time, because the first read already set it.
|
|
33
|
+
for (const file of runEnvironmentFiles(existsSync)) {
|
|
34
|
+
process.loadEnvFile(file);
|
|
35
|
+
}
|
|
36
|
+
// Vitest re-runs a setup module once per spec file, while the builtins it patches live for the whole
|
|
37
|
+
// worker. Without a mark, each file would wrap the previous file's wrapper one layer deeper.
|
|
38
|
+
const GUARD_MARK = Symbol.for('ploaness.network-guard');
|
|
39
|
+
const MACHINE_ADDRESSES = localAddresses(os.networkInterfaces());
|
|
40
|
+
const refuse = (attempt) => {
|
|
41
|
+
const refusal = findNetworkEscape(attempt, MACHINE_ADDRESSES);
|
|
42
|
+
if (refusal !== undefined) {
|
|
43
|
+
throw new Error(refusal);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
// A proxy rather than a wrapper function, for two reasons that both come from what is being wrapped.
|
|
47
|
+
// `net.Socket.prototype.connect` is a method, so the receiver has to reach the original - and a proxy
|
|
48
|
+
// forwards it without the wrapper ever naming `this`. And `dns.lookup` announces its promisified shape
|
|
49
|
+
// through a symbol property, which a hand-written wrapper has to remember to copy and a proxy carries
|
|
50
|
+
// by construction, along with the function's name and arity.
|
|
51
|
+
const guard = (original, toAttempt) => new Proxy(original, {
|
|
52
|
+
// Annotated rather than inherited from `ProxyHandler`, whose own declaration types the receiver and
|
|
53
|
+
// the argument list as `any`; taking that would put two `any` values into the single function every
|
|
54
|
+
// network call in the suite passes through.
|
|
55
|
+
apply: (target, receiver, callArguments) => {
|
|
56
|
+
refuse(toAttempt(callArguments));
|
|
57
|
+
const result = Reflect.apply(target, receiver, callArguments);
|
|
58
|
+
return result;
|
|
59
|
+
},
|
|
60
|
+
has: (target, key) => key === GUARD_MARK || Reflect.has(target, key),
|
|
61
|
+
});
|
|
62
|
+
// Installed non-writable and non-configurable, so a project setup file or a spec body cannot put the
|
|
63
|
+
// original back. Installing it twice is not a no-op but an error, which is what the mark check prevents.
|
|
64
|
+
const install = (owner, key, toAttempt) => {
|
|
65
|
+
const original = Reflect.get(owner, key);
|
|
66
|
+
if (!isIntercepted(original) || Reflect.has(original, GUARD_MARK)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
Object.defineProperty(owner, key, {
|
|
70
|
+
value: guard(original, toAttempt),
|
|
71
|
+
writable: false,
|
|
72
|
+
enumerable: Object.getOwnPropertyDescriptor(owner, key)?.enumerable ?? true,
|
|
73
|
+
configurable: false,
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const firstArgumentOf = (callArguments) => {
|
|
77
|
+
const [target] = callArguments;
|
|
78
|
+
return typeof target === 'string' ? target : String(target);
|
|
79
|
+
};
|
|
80
|
+
const toLookupAttempt = (callArguments) => ({
|
|
81
|
+
api: 'lookup',
|
|
82
|
+
host: firstArgumentOf(callArguments),
|
|
83
|
+
destination: firstArgumentOf(callArguments),
|
|
84
|
+
});
|
|
85
|
+
const toResolveAttempt = (callArguments) => ({
|
|
86
|
+
api: 'resolve',
|
|
87
|
+
host: firstArgumentOf(callArguments),
|
|
88
|
+
destination: firstArgumentOf(callArguments),
|
|
89
|
+
});
|
|
90
|
+
// `fetch` accepts a string, a `URL`, or a `Request`, and each yields its address differently. A single
|
|
91
|
+
// `String(...)` over that union stringifies a `Request` to `[object Object]`, which would make the
|
|
92
|
+
// refusal name nothing a reader could act on.
|
|
93
|
+
const fetchTargetUrl = (target) => {
|
|
94
|
+
if (typeof target === 'string') {
|
|
95
|
+
return target;
|
|
96
|
+
}
|
|
97
|
+
if (target instanceof URL) {
|
|
98
|
+
return target.href;
|
|
99
|
+
}
|
|
100
|
+
const declared = isRecord(target) ? target['url'] : undefined;
|
|
101
|
+
return typeof declared === 'string' ? declared : '';
|
|
102
|
+
};
|
|
103
|
+
const toFetchAttempt = (callArguments) => {
|
|
104
|
+
const [target] = callArguments;
|
|
105
|
+
const raw = fetchTargetUrl(target);
|
|
106
|
+
return { api: 'fetch', host: hostOfUrl(raw), destination: raw };
|
|
107
|
+
};
|
|
108
|
+
// The chokepoint. Every TCP reach in Node passes through it - `net.connect`, the http and https agents,
|
|
109
|
+
// `tls.connect` (a TLSSocket inherits this method rather than declaring its own), http2, undici and so
|
|
110
|
+
// the global fetch, and every database driver. Guarding it alone would already be the whole rule.
|
|
111
|
+
install(net.Socket.prototype, 'connect', describeSocketTarget);
|
|
112
|
+
// Redundant with the socket guard for anything that goes on to connect, and worth having anyway: it
|
|
113
|
+
// names the host rather than the socket, and it catches a caller that resolves before deciding where to
|
|
114
|
+
// go.
|
|
115
|
+
install(dns, 'lookup', toLookupAttempt);
|
|
116
|
+
install(dns.promises, 'lookup', toLookupAttempt);
|
|
117
|
+
// The hole the socket guard does not cover. The resolver family queries a nameserver over UDP without
|
|
118
|
+
// ever creating a socket, which is how an SRV lookup leaves the machine with nothing to intercept.
|
|
119
|
+
//
|
|
120
|
+
// The module-level `dns.resolve*` functions are bound to a default Resolver instance, so patching them
|
|
121
|
+
// leaves `new dns.Resolver().resolveSrv(...)` reaching `Resolver.prototype` untouched - the exact hole
|
|
122
|
+
// this block exists to close, one constructor away. The prototypes are guarded too.
|
|
123
|
+
// Named without a presence check: both constructors are declared by node's own types, so an optional
|
|
124
|
+
// chain here would be a defence against a shape the runtime cannot have and the compiler already denies.
|
|
125
|
+
const resolverOwners = [
|
|
126
|
+
dns,
|
|
127
|
+
dns.promises,
|
|
128
|
+
dns.Resolver.prototype,
|
|
129
|
+
dns.promises.Resolver.prototype,
|
|
130
|
+
];
|
|
131
|
+
for (const method of RESOLVER_METHODS) {
|
|
132
|
+
for (const owner of resolverOwners) {
|
|
133
|
+
install(owner, method, toResolveAttempt);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Left replaceable, unlike the two above. A DOM test environment swaps the globals between files, and a
|
|
137
|
+
// non-configurable `fetch` would break that swap. This layer exists for the message it produces; if it
|
|
138
|
+
// is replaced, the socket guard still refuses the request one layer down.
|
|
139
|
+
// Read through Reflect rather than as a bare name: a runtime without it would make the bare name a
|
|
140
|
+
// reference error rather than an absence to skip over.
|
|
141
|
+
const currentFetch = Reflect.get(globalThis, 'fetch');
|
|
142
|
+
if (isIntercepted(currentFetch) && !Reflect.has(currentFetch, GUARD_MARK)) {
|
|
143
|
+
Object.defineProperty(globalThis, 'fetch', {
|
|
144
|
+
value: guard(currentFetch, toFetchAttempt),
|
|
145
|
+
writable: true,
|
|
146
|
+
enumerable: false,
|
|
147
|
+
configurable: true,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=vitest-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest-setup.js","sourceRoot":"","sources":["../src/vitest-setup.ts"],"names":[],"mappings":"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"}
|
package/dist/vitest.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AAmIA,QAAA,MAAM,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAmB,CAAA;AAEjE,eAAe,MAAM,CAAA"}
|
package/dist/vitest.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// The Vitest configuration ploaness owns. A consuming project re-exports it verbatim; the only
|
|
2
|
+
// project-specific input is the coverage exclusion list, which the project declares under the `ploaness`
|
|
3
|
+
// key of its package.json rather than by editing this file.
|
|
4
|
+
//
|
|
5
|
+
// The coverage policy is default-safe, which is the point: EVERY TypeScript module under the declared
|
|
6
|
+
// source roots is in scope, and exemptions are carved out by ROLE, never by naming a handful of folders
|
|
7
|
+
// that happen to have tests today. A new logic directory is therefore covered the moment it exists,
|
|
8
|
+
// instead of silently escaping an allowlist nobody remembered to extend. With `include` set, Vitest
|
|
9
|
+
// counts every matching file even when no test imports it, so an untested unit scores zero and fails the
|
|
10
|
+
// gate rather than being invisible.
|
|
11
|
+
import { COVERAGE_INCLUDE } from '@ploaness/governance';
|
|
12
|
+
import react from '@vitejs/plugin-react';
|
|
13
|
+
import { defineConfig } from 'vitest/config';
|
|
14
|
+
import { projectSettings as settings } from './project-settings.js';
|
|
15
|
+
import { COVERAGE_THRESHOLD, DETERMINISTIC_SEQUENCE, harnessSetupFile, projectSetupFiles, testReporters, } from './vitest-core.js';
|
|
16
|
+
// The environment is per suite rather than per repository, and that split is load-bearing rather than
|
|
17
|
+
// tidy. `jsdom` installs its OWN realm's globals, typed-array constructors included, so a Node `Buffer`
|
|
18
|
+
// fails `input instanceof Uint8Array` inside any library that guards its input that way - the check
|
|
19
|
+
// compares constructor identity, not shape. Payload's upload pipeline does exactly that, through
|
|
20
|
+
// `file-type`, and wraps the resulting TypeError in a `ValidationError` on the `file` field. The
|
|
21
|
+
// consequence was that no Payload project running this config could integration-test an upload against
|
|
22
|
+
// an `upload.mimeTypes` allowlist: the suite reported the project's own allowlist rejecting a valid PNG,
|
|
23
|
+
// which is a defect in this file wearing the costume of a defect in the project's security policy.
|
|
24
|
+
//
|
|
25
|
+
// So an integration spec, which boots the server-side application and has no DOM to want, runs under
|
|
26
|
+
// `node`. A unit spec keeps `jsdom`: `tests/component/**` is where a spec that needs a DOM belongs, but
|
|
27
|
+
// a `.ts` unit spec reaching for `document` is a shape consumers already have, and taking it away is a
|
|
28
|
+
// different decision from this one.
|
|
29
|
+
const SUITES = [
|
|
30
|
+
{
|
|
31
|
+
name: 'node',
|
|
32
|
+
environment: 'node',
|
|
33
|
+
include: ['tests/int/**/*.int.spec.ts', 'tests/int/**/*.int.spec.tsx'],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'jsdom',
|
|
37
|
+
environment: 'jsdom',
|
|
38
|
+
include: [
|
|
39
|
+
'tests/unit/**/*.unit.spec.ts',
|
|
40
|
+
// A component spec had no home. ploaness pins and ships React Testing Library, jest-dom,
|
|
41
|
+
// user-event and a jsdom environment - a stack that exists for exactly this - while collecting
|
|
42
|
+
// only `.ts` under unit and anything under int. So a project writing the component tests the
|
|
43
|
+
// harness equips it for had to mislabel them as integration tests or watch them silently stop
|
|
44
|
+
// running, which is what a real consumer's suite was doing when this was found.
|
|
45
|
+
'tests/component/**/*.component.spec.tsx',
|
|
46
|
+
'tests/component/**/*.component.spec.ts',
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
// Every suite carries the guards, because a project gets its own Vite server and inherits nothing from
|
|
51
|
+
// the root unless it says so. The plugin is constructed per suite rather than shared: two servers
|
|
52
|
+
// holding one plugin instance would share whatever state it keeps.
|
|
53
|
+
const suiteProject = (suite) => ({
|
|
54
|
+
plugins: [react()],
|
|
55
|
+
// Vite resolves the project's path aliases from tsconfig natively, so no extra plugin is needed.
|
|
56
|
+
resolve: { tsconfigPaths: true },
|
|
57
|
+
test: {
|
|
58
|
+
name: suite.name,
|
|
59
|
+
environment: suite.environment,
|
|
60
|
+
include: [...suite.include],
|
|
61
|
+
// The harness file first, and `sequence.setupFiles: 'list'` makes that ordering binding rather
|
|
62
|
+
// than incidental: it installs the network guard, which has to be in place before a project's own
|
|
63
|
+
// setup runs. A project cannot reach either entry - its vitest.config.mts is a bare re-export of
|
|
64
|
+
// this file, and the `tests` gate builds its own argv.
|
|
65
|
+
setupFiles: [harnessSetupFile(), ...projectSetupFiles()],
|
|
66
|
+
sequence: DETERMINISTIC_SEQUENCE,
|
|
67
|
+
// Run spec files one at a time. Each top-level test command gets one ephemeral database, but every
|
|
68
|
+
// Payload-booting spec within that command shares it; in parallel, two boots could race to CREATE
|
|
69
|
+
// the same enum or table. Serial boots make the first push establish the schema and later boots find
|
|
70
|
+
// it already present, which is idempotent.
|
|
71
|
+
//
|
|
72
|
+
// Declared on every suite, not once at the root: Vitest collapses the suites into a single serial
|
|
73
|
+
// group only when each one asks for a single worker, so a suite that omitted this would run
|
|
74
|
+
// alongside the others and put the shared database back in a race.
|
|
75
|
+
fileParallelism: false,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
// Structural rather than Vite's own `UserConfig`, and the annotation is load-bearing rather than
|
|
79
|
+
// stylistic. An emitted declaration naming `import('vite').UserConfig` would make `vite` resolvable
|
|
80
|
+
// from this package a condition of type-checking a consumer's `vitest.config.mts` - and `vite` arrives
|
|
81
|
+
// here only as a transitive dependency of `vitest`, which pnpm's strict layout does not expose. The
|
|
82
|
+
// consumer re-exports this value and never reads a field off it, so the shape is all it needs. The
|
|
83
|
+
// hand-written declaration this file replaced recorded the same decision.
|
|
84
|
+
// `ReturnType` rather than the runner's own exported type: naming that type would import it, which is
|
|
85
|
+
// the dependency the annotation below exists to avoid. This binding is module-local, so it reaches no
|
|
86
|
+
// declaration file either way.
|
|
87
|
+
const declared = defineConfig({
|
|
88
|
+
test: {
|
|
89
|
+
projects: SUITES.map((suite) => suiteProject(suite)),
|
|
90
|
+
// Root-only, like coverage below: a reporter reports on the run rather than on one suite.
|
|
91
|
+
reporters: [...testReporters()],
|
|
92
|
+
// Coverage stays at the root because Vitest forbids it anywhere else: it is one measurement over
|
|
93
|
+
// the whole verification rather than a property of any one suite.
|
|
94
|
+
coverage: {
|
|
95
|
+
provider: 'v8',
|
|
96
|
+
reporter: ['text', 'html', 'lcov'],
|
|
97
|
+
// Imported rather than written here: the exclusion-reach rule judges a declared exclusion against
|
|
98
|
+
// exactly this set, and a second copy of it would decide a verdict the report never agreed with.
|
|
99
|
+
include: [...COVERAGE_INCLUDE],
|
|
100
|
+
exclude: [...settings.coverageExclude],
|
|
101
|
+
thresholds: {
|
|
102
|
+
// perFile: every covered file must independently clear the bar. Without it one fully covered
|
|
103
|
+
// file can mask an uncovered one in the aggregate, which is exactly how an untested helper hides.
|
|
104
|
+
perFile: true,
|
|
105
|
+
lines: COVERAGE_THRESHOLD,
|
|
106
|
+
branches: COVERAGE_THRESHOLD,
|
|
107
|
+
functions: COVERAGE_THRESHOLD,
|
|
108
|
+
statements: COVERAGE_THRESHOLD,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
// A shallow copy rather than an assertion: a spread yields an anonymous object type, which carries
|
|
114
|
+
// the index signature an interface does not, so the structural annotation above holds without one.
|
|
115
|
+
const config = { ...declared };
|
|
116
|
+
export default config;
|
|
117
|
+
//# sourceMappingURL=vitest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"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"}
|