@projitect/blueprint-vitest 0.0.0-stage → 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kapil Easwar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@projitect/blueprint-vitest",
3
+ "version": "1.0.0",
4
+ "description": "Vitest scaffolding blueprint for projitect — owns vitest.config.ts, package.json scripts/devDeps, and the .gitignore coverage entry.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/projitect/projitect.git",
8
+ "directory": "packages/blueprint-vitest"
9
+ },
10
+ "license": "MIT",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/src/index.d.ts",
15
+ "import": "./dist/src/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src",
21
+ "!**/*.tsbuildinfo"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc --build",
25
+ "build:clean": "tsc --build --clean",
26
+ "tc": "tsc --build"
27
+ },
28
+ "devDependencies": {
29
+ "@projitect/blueprint": "workspace:*",
30
+ "@projitect/core": "workspace:*",
31
+ "@projitect/test-kit": "workspace:*",
32
+ "effect": "4.0.0-rc.111",
33
+ "typescript": "5.9.3"
34
+ },
35
+ "peerDependencies": {
36
+ "@projitect/blueprint": "workspace:*",
37
+ "@projitect/core": "workspace:*",
38
+ "effect": "4.0.0-rc.111"
39
+ },
40
+ "engines": {
41
+ "node": ">=22.12.0"
42
+ },
43
+ "projitect": {
44
+ "type": "blueprint",
45
+ "import": "import { vitest } from \"@projitect/blueprint-vitest\"",
46
+ "call": "vitest()"
47
+ }
48
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @projitect/blueprint-vitest
3
+ *
4
+ * One composite blueprint that wires vitest into a project:
5
+ *
6
+ * 1. Adds `vitest` and (optionally) `@vitest/coverage-v8` to `package.json`'s `devDependencies`,
7
+ * plus `test` / `test:watch` scripts. Merge mode — non-conflicting with whatever else lives
8
+ * in `package.json`.
9
+ * 2. Owns `vitest.config.ts` with sensible defaults (NodeNext-friendly, v8 coverage). Owned
10
+ * mode — projitect rewrites this file from scratch on every `remodel` so the user can't
11
+ * accidentally drift it. If the user wants project-specific overrides, they should compose
12
+ * this blueprint with their own `ownFile` blueprint at a different path.
13
+ * 3. Adds `coverage/` to `.gitignore`. Region mode — coexists with whatever else is in the file
14
+ * (including other projitect blueprints like `@projitect/blueprint-gitignore`).
15
+ *
16
+ * This is the smallest framework blueprint we ship after gitignore. It validates merge mode +
17
+ * owned mode + region mode in one move, and it's the first time the projitect blueprint won't
18
+ * be the *only* merge-mode consumer in a real project.
19
+ */
20
+ import type { Blueprint } from "@projitect/core";
21
+ /**
22
+ * Options for the vitest blueprint. All optional; defaults give a working setup.
23
+ */
24
+ export interface VitestOptions {
25
+ /**
26
+ * Coverage provider. Defaults to `"v8"`. Set to `null` to skip the coverage devDep and the
27
+ * `.gitignore` coverage entry (you'll get vitest without coverage configured).
28
+ */
29
+ readonly coverage?: "v8" | null;
30
+ /**
31
+ * Override the script name for the one-shot test runner. Defaults to `"test"`.
32
+ * The watch variant is always `<scriptName>:watch`.
33
+ */
34
+ readonly scriptName?: string;
35
+ /**
36
+ * Test environment. Defaults to `"node"` (matches vitest's default). Set to `"jsdom"` if you
37
+ * want DOM globals — you'll also need to install `jsdom` separately; this blueprint does not
38
+ * add it because not every consumer needs it.
39
+ */
40
+ readonly environment?: "node" | "jsdom";
41
+ }
42
+ /**
43
+ * Build the composite vitest blueprint. The returned `Blueprint` emits three to four operations
44
+ * depending on options; the planner / lockfile track each separately so the user gets fine-
45
+ * grained drift reporting (e.g. "package.json merge drift on devDependencies.vitest" rather than
46
+ * a vague "blueprint drift").
47
+ */
48
+ export declare const vitest: (options?: VitestOptions) => Blueprint.Blueprint;
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAWhD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAC/B;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACxC;AAED;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GAAI,UAAS,aAAkB,KAAG,SAAS,CAAC,SA+E9D,CAAA"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @projitect/blueprint-vitest
3
+ *
4
+ * One composite blueprint that wires vitest into a project:
5
+ *
6
+ * 1. Adds `vitest` and (optionally) `@vitest/coverage-v8` to `package.json`'s `devDependencies`,
7
+ * plus `test` / `test:watch` scripts. Merge mode — non-conflicting with whatever else lives
8
+ * in `package.json`.
9
+ * 2. Owns `vitest.config.ts` with sensible defaults (NodeNext-friendly, v8 coverage). Owned
10
+ * mode — projitect rewrites this file from scratch on every `remodel` so the user can't
11
+ * accidentally drift it. If the user wants project-specific overrides, they should compose
12
+ * this blueprint with their own `ownFile` blueprint at a different path.
13
+ * 3. Adds `coverage/` to `.gitignore`. Region mode — coexists with whatever else is in the file
14
+ * (including other projitect blueprints like `@projitect/blueprint-gitignore`).
15
+ *
16
+ * This is the smallest framework blueprint we ship after gitignore. It validates merge mode +
17
+ * owned mode + region mode in one move, and it's the first time the projitect blueprint won't
18
+ * be the *only* merge-mode consumer in a real project.
19
+ */
20
+ import { Effect } from "effect";
21
+ import { regionFile, jsonMerge, ownFile } from "@projitect/blueprint";
22
+ import { ChangeSet as CS } from "@projitect/core";
23
+ import manifest from "../package.json" with { type: "json" };
24
+ // Read the version from the package manifest (emitted next to `dist/src`) so a release bump
25
+ // reaches `.pjt.lock` without a hand-edited constant. JSON import keeps this runtime-pure.
26
+ const PACKAGE_VERSION = manifest.version;
27
+ const VITEST_DEP_RANGE = "^4.0.0";
28
+ const COVERAGE_V8_DEP_RANGE = "^4.0.0";
29
+ /**
30
+ * Build the composite vitest blueprint. The returned `Blueprint` emits three to four operations
31
+ * depending on options; the planner / lockfile track each separately so the user gets fine-
32
+ * grained drift reporting (e.g. "package.json merge drift on devDependencies.vitest" rather than
33
+ * a vague "blueprint drift").
34
+ */
35
+ export const vitest = (options = {}) => {
36
+ const coverage = options.coverage === undefined ? "v8" : options.coverage;
37
+ const scriptName = options.scriptName ?? "test";
38
+ const watchScript = `${scriptName}:watch`;
39
+ const environment = options.environment ?? "node";
40
+ const id = "pjt:vitest";
41
+ // We compose four constructor blueprints inline rather than handing four separate Blueprint
42
+ // entries to the user — that way `pjt add @projitect/blueprint-vitest` adds one call line, and
43
+ // every drift / removal is attributed to `pjt:vitest`. The composite plan just `Effect.all`s
44
+ // their `plan` Effects and concatenates the resulting ChangeSets.
45
+ const packageJsonMerge = jsonMerge({
46
+ id,
47
+ version: PACKAGE_VERSION,
48
+ description: "vitest devDependencies and test scripts",
49
+ path: "package.json",
50
+ ownedKeys: [
51
+ `scripts.${scriptName}`,
52
+ `scripts.${watchScript}`,
53
+ "devDependencies.vitest",
54
+ ...(coverage === "v8" ? ["devDependencies.@vitest/coverage-v8"] : []),
55
+ ],
56
+ value: {
57
+ scripts: {
58
+ [scriptName]: "vitest run",
59
+ [watchScript]: "vitest",
60
+ },
61
+ devDependencies: {
62
+ vitest: VITEST_DEP_RANGE,
63
+ ...(coverage === "v8" && { "@vitest/coverage-v8": COVERAGE_V8_DEP_RANGE }),
64
+ },
65
+ },
66
+ });
67
+ const vitestConfig = ownFile({
68
+ id,
69
+ version: PACKAGE_VERSION,
70
+ description: "vitest configuration",
71
+ path: "vitest.config.ts",
72
+ content: renderVitestConfig({ coverage, environment }),
73
+ });
74
+ const gitignoreCoverage = coverage === "v8"
75
+ ? regionFile({
76
+ id,
77
+ version: PACKAGE_VERSION,
78
+ description: "ignore vitest coverage output",
79
+ path: ".gitignore",
80
+ commentPrefix: "#",
81
+ content: "coverage/\n",
82
+ })
83
+ : null;
84
+ const composite = {
85
+ id,
86
+ version: PACKAGE_VERSION,
87
+ description: "vitest scaffolding (config + scripts + devDeps + coverage gitignore)",
88
+ permissions: [
89
+ { kind: "read", glob: "package.json" },
90
+ { kind: "write", glob: "package.json" },
91
+ { kind: "write", glob: "vitest.config.ts" },
92
+ { kind: "read", glob: ".gitignore" },
93
+ { kind: "write", glob: ".gitignore" },
94
+ ],
95
+ plan: Effect.gen(function* () {
96
+ const parts = [
97
+ packageJsonMerge,
98
+ vitestConfig,
99
+ ...(gitignoreCoverage === null ? [] : [gitignoreCoverage]),
100
+ ];
101
+ const changeSets = yield* Effect.forEach(parts, (b) => b.plan);
102
+ return CS.Reducer.combineAll(changeSets);
103
+ }),
104
+ };
105
+ return composite;
106
+ };
107
+ const renderVitestConfig = (params) => {
108
+ const lines = [
109
+ 'import { defineConfig } from "vitest/config"',
110
+ "",
111
+ "/**",
112
+ " * vitest configuration scaffolded by `@projitect/blueprint-vitest`.",
113
+ " *",
114
+ " * Owned mode — projitect rewrites this file on every `pjt remodel`. If you need overrides,",
115
+ " * compose another `ownFile` blueprint at a different path (e.g. `vitest.config.local.ts`)",
116
+ " * and merge it into this config via vitest's own `mergeConfig` helper at runtime.",
117
+ " */",
118
+ "export default defineConfig({",
119
+ " test: {",
120
+ ` environment: "${params.environment}",`,
121
+ " passWithNoTests: true,",
122
+ ];
123
+ if (params.coverage === "v8") {
124
+ lines.push(" coverage: {", ' provider: "v8",', ' reporter: ["text", "html"],', " },");
125
+ }
126
+ lines.push(" },", "})", "");
127
+ return lines.join("\n");
128
+ };
129
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@projitect/blueprint-vitest",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "description": "Vitest scaffolding blueprint for projitect — owns vitest.config.ts, package.json scripts/devDeps, and the .gitignore coverage entry.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/projitect/projitect.git",
8
+ "directory": "packages/blueprint-vitest"
9
+ },
10
+ "license": "MIT",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/src/index.d.ts",
15
+ "import": "./dist/src/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src",
21
+ "!**/*.tsbuildinfo"
22
+ ],
23
+ "devDependencies": {
24
+ "effect": "4.0.0-rc.111",
25
+ "typescript": "5.9.3",
26
+ "@projitect/blueprint": "1.0.0",
27
+ "@projitect/core": "1.0.0",
28
+ "@projitect/test-kit": "1.0.0"
29
+ },
30
+ "peerDependencies": {
31
+ "effect": "4.0.0-rc.111",
32
+ "@projitect/blueprint": "1.0.0",
33
+ "@projitect/core": "1.0.0"
34
+ },
35
+ "engines": {
36
+ "node": ">=22.12.0"
37
+ },
38
+ "projitect": {
39
+ "type": "blueprint",
40
+ "import": "import { vitest } from \"@projitect/blueprint-vitest\"",
41
+ "call": "vitest()"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc --build",
45
+ "build:clean": "tsc --build --clean",
46
+ "tc": "tsc --build"
47
+ }
6
48
  }
package/src/index.ts ADDED
@@ -0,0 +1,174 @@
1
+ /**
2
+ * @projitect/blueprint-vitest
3
+ *
4
+ * One composite blueprint that wires vitest into a project:
5
+ *
6
+ * 1. Adds `vitest` and (optionally) `@vitest/coverage-v8` to `package.json`'s `devDependencies`,
7
+ * plus `test` / `test:watch` scripts. Merge mode — non-conflicting with whatever else lives
8
+ * in `package.json`.
9
+ * 2. Owns `vitest.config.ts` with sensible defaults (NodeNext-friendly, v8 coverage). Owned
10
+ * mode — projitect rewrites this file from scratch on every `remodel` so the user can't
11
+ * accidentally drift it. If the user wants project-specific overrides, they should compose
12
+ * this blueprint with their own `ownFile` blueprint at a different path.
13
+ * 3. Adds `coverage/` to `.gitignore`. Region mode — coexists with whatever else is in the file
14
+ * (including other projitect blueprints like `@projitect/blueprint-gitignore`).
15
+ *
16
+ * This is the smallest framework blueprint we ship after gitignore. It validates merge mode +
17
+ * owned mode + region mode in one move, and it's the first time the projitect blueprint won't
18
+ * be the *only* merge-mode consumer in a real project.
19
+ */
20
+
21
+ import { Effect } from "effect"
22
+ import { regionFile, jsonMerge, ownFile } from "@projitect/blueprint"
23
+ import type { Blueprint } from "@projitect/core"
24
+ import { ChangeSet as CS } from "@projitect/core"
25
+ import manifest from "../package.json" with { type: "json" }
26
+
27
+ // Read the version from the package manifest (emitted next to `dist/src`) so a release bump
28
+ // reaches `.pjt.lock` without a hand-edited constant. JSON import keeps this runtime-pure.
29
+ const PACKAGE_VERSION = manifest.version
30
+
31
+ const VITEST_DEP_RANGE = "^4.0.0"
32
+ const COVERAGE_V8_DEP_RANGE = "^4.0.0"
33
+
34
+ /**
35
+ * Options for the vitest blueprint. All optional; defaults give a working setup.
36
+ */
37
+ export interface VitestOptions {
38
+ /**
39
+ * Coverage provider. Defaults to `"v8"`. Set to `null` to skip the coverage devDep and the
40
+ * `.gitignore` coverage entry (you'll get vitest without coverage configured).
41
+ */
42
+ readonly coverage?: "v8" | null
43
+ /**
44
+ * Override the script name for the one-shot test runner. Defaults to `"test"`.
45
+ * The watch variant is always `<scriptName>:watch`.
46
+ */
47
+ readonly scriptName?: string
48
+ /**
49
+ * Test environment. Defaults to `"node"` (matches vitest's default). Set to `"jsdom"` if you
50
+ * want DOM globals — you'll also need to install `jsdom` separately; this blueprint does not
51
+ * add it because not every consumer needs it.
52
+ */
53
+ readonly environment?: "node" | "jsdom"
54
+ }
55
+
56
+ /**
57
+ * Build the composite vitest blueprint. The returned `Blueprint` emits three to four operations
58
+ * depending on options; the planner / lockfile track each separately so the user gets fine-
59
+ * grained drift reporting (e.g. "package.json merge drift on devDependencies.vitest" rather than
60
+ * a vague "blueprint drift").
61
+ */
62
+ export const vitest = (options: VitestOptions = {}): Blueprint.Blueprint => {
63
+ const coverage = options.coverage === undefined ? "v8" : options.coverage
64
+ const scriptName = options.scriptName ?? "test"
65
+ const watchScript = `${scriptName}:watch`
66
+ const environment = options.environment ?? "node"
67
+
68
+ const id = "pjt:vitest"
69
+
70
+ // We compose four constructor blueprints inline rather than handing four separate Blueprint
71
+ // entries to the user — that way `pjt add @projitect/blueprint-vitest` adds one call line, and
72
+ // every drift / removal is attributed to `pjt:vitest`. The composite plan just `Effect.all`s
73
+ // their `plan` Effects and concatenates the resulting ChangeSets.
74
+
75
+ const packageJsonMerge = jsonMerge({
76
+ id,
77
+ version: PACKAGE_VERSION,
78
+ description: "vitest devDependencies and test scripts",
79
+ path: "package.json",
80
+ ownedKeys: [
81
+ `scripts.${scriptName}`,
82
+ `scripts.${watchScript}`,
83
+ "devDependencies.vitest",
84
+ ...(coverage === "v8" ? ["devDependencies.@vitest/coverage-v8" as const] : []),
85
+ ],
86
+ value: {
87
+ scripts: {
88
+ [scriptName]: "vitest run",
89
+ [watchScript]: "vitest",
90
+ },
91
+ devDependencies: {
92
+ vitest: VITEST_DEP_RANGE,
93
+ ...(coverage === "v8" && { "@vitest/coverage-v8": COVERAGE_V8_DEP_RANGE }),
94
+ },
95
+ },
96
+ })
97
+
98
+ const vitestConfig = ownFile({
99
+ id,
100
+ version: PACKAGE_VERSION,
101
+ description: "vitest configuration",
102
+ path: "vitest.config.ts",
103
+ content: renderVitestConfig({ coverage, environment }),
104
+ })
105
+
106
+ const gitignoreCoverage =
107
+ coverage === "v8"
108
+ ? regionFile({
109
+ id,
110
+ version: PACKAGE_VERSION,
111
+ description: "ignore vitest coverage output",
112
+ path: ".gitignore",
113
+ commentPrefix: "#",
114
+ content: "coverage/\n",
115
+ })
116
+ : null
117
+
118
+ const composite: Blueprint.Blueprint = {
119
+ id,
120
+ version: PACKAGE_VERSION,
121
+ description: "vitest scaffolding (config + scripts + devDeps + coverage gitignore)",
122
+ permissions: [
123
+ { kind: "read", glob: "package.json" },
124
+ { kind: "write", glob: "package.json" },
125
+ { kind: "write", glob: "vitest.config.ts" },
126
+ { kind: "read", glob: ".gitignore" },
127
+ { kind: "write", glob: ".gitignore" },
128
+ ],
129
+ plan: Effect.gen(function* () {
130
+ const parts = [
131
+ packageJsonMerge,
132
+ vitestConfig,
133
+ ...(gitignoreCoverage === null ? [] : [gitignoreCoverage]),
134
+ ]
135
+ const changeSets = yield* Effect.forEach(parts, (b) => b.plan)
136
+ return CS.Reducer.combineAll(changeSets)
137
+ }),
138
+ }
139
+
140
+ return composite
141
+ }
142
+
143
+ const renderVitestConfig = (params: {
144
+ readonly coverage: "v8" | null
145
+ readonly environment: "node" | "jsdom"
146
+ }): string => {
147
+ const lines: string[] = [
148
+ 'import { defineConfig } from "vitest/config"',
149
+ "",
150
+ "/**",
151
+ " * vitest configuration scaffolded by `@projitect/blueprint-vitest`.",
152
+ " *",
153
+ " * Owned mode — projitect rewrites this file on every `pjt remodel`. If you need overrides,",
154
+ " * compose another `ownFile` blueprint at a different path (e.g. `vitest.config.local.ts`)",
155
+ " * and merge it into this config via vitest's own `mergeConfig` helper at runtime.",
156
+ " */",
157
+ "export default defineConfig({",
158
+ " test: {",
159
+ ` environment: "${params.environment}",`,
160
+ " passWithNoTests: true,",
161
+ ]
162
+
163
+ if (params.coverage === "v8") {
164
+ lines.push(
165
+ " coverage: {",
166
+ ' provider: "v8",',
167
+ ' reporter: ["text", "html"],',
168
+ " },",
169
+ )
170
+ }
171
+
172
+ lines.push(" },", "})", "")
173
+ return lines.join("\n")
174
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.