@interfere/vitest-config 1.0.0 → 1.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/library.ts +171 -6
- package/package.json +4 -4
package/CHANGELOG.md
ADDED
package/library.ts
CHANGED
|
@@ -1,6 +1,160 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
import { configDefaults, defineConfig } from "vitest/config";
|
|
6
|
+
|
|
7
|
+
// Find monorepo root by walking up from this config file
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
const findRoot = (dir: string): string => {
|
|
11
|
+
if (existsSync(resolve(dir, "pnpm-workspace.yaml"))) {
|
|
12
|
+
return dir;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const parent = dirname(dir);
|
|
16
|
+
|
|
17
|
+
if (parent === dir) {
|
|
18
|
+
throw new Error("Could not find monorepo root");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return findRoot(parent);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const root = findRoot(__dirname);
|
|
25
|
+
|
|
26
|
+
type PackageImportsMap = Record<
|
|
27
|
+
string,
|
|
28
|
+
{ "@source"?: string; default?: string; types?: string }
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
const packageJsonCache = new Map<
|
|
32
|
+
string,
|
|
33
|
+
{ root: string; imports: PackageImportsMap } | null
|
|
34
|
+
>();
|
|
35
|
+
|
|
36
|
+
const findPackageRootForFile = (startFile: string) => {
|
|
37
|
+
let dir = dirname(startFile);
|
|
38
|
+
|
|
39
|
+
while (dir.startsWith(root)) {
|
|
40
|
+
const pj = resolve(dir, "package.json");
|
|
41
|
+
if (existsSync(pj)) {
|
|
42
|
+
return dir;
|
|
43
|
+
}
|
|
44
|
+
const parent = dirname(dir);
|
|
45
|
+
|
|
46
|
+
if (parent === dir) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
dir = parent;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const getPackageImportsForFile = (filePath: string) => {
|
|
56
|
+
const pkgRoot = findPackageRootForFile(filePath);
|
|
57
|
+
if (!pkgRoot) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const cached = packageJsonCache.get(pkgRoot);
|
|
62
|
+
if (cached !== undefined) {
|
|
63
|
+
return cached;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const raw = readFileSync(resolve(pkgRoot, "package.json"), "utf8");
|
|
68
|
+
const parsed = JSON.parse(raw) as { imports?: PackageImportsMap };
|
|
69
|
+
const value = { root: pkgRoot, imports: parsed.imports ?? {} };
|
|
70
|
+
packageJsonCache.set(pkgRoot, value);
|
|
71
|
+
return value;
|
|
72
|
+
} catch {
|
|
73
|
+
packageJsonCache.set(pkgRoot, null);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const resolveSubpathImport = (
|
|
79
|
+
id: string,
|
|
80
|
+
importer: string | undefined
|
|
81
|
+
): string | null => {
|
|
82
|
+
const getMappedTargetPath = (target: {
|
|
83
|
+
"@source"?: string;
|
|
84
|
+
default?: string;
|
|
85
|
+
}) => target["@source"] ?? target.default ?? null;
|
|
86
|
+
|
|
87
|
+
const getWildcardMatch = (pattern: string, specifier: string) => {
|
|
88
|
+
const starIndex = pattern.indexOf("*");
|
|
89
|
+
if (starIndex === -1) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const prefix = pattern.slice(0, starIndex);
|
|
94
|
+
const suffix = pattern.slice(starIndex + 1);
|
|
95
|
+
if (!(specifier.startsWith(prefix) && specifier.endsWith(suffix))) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return specifier.slice(prefix.length, specifier.length - suffix.length);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const pkg = getPackageImportsForFile(
|
|
103
|
+
importer ?? resolve(process.cwd(), "package.json")
|
|
104
|
+
);
|
|
105
|
+
if (!pkg) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const entries = Object.entries(pkg.imports);
|
|
110
|
+
|
|
111
|
+
const exact = entries.find(([key]) => key === id);
|
|
112
|
+
if (exact) {
|
|
113
|
+
const mapped = getMappedTargetPath(exact[1]);
|
|
114
|
+
if (!mapped) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return resolve(pkg.root, mapped);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (const [key, target] of entries) {
|
|
122
|
+
const match = getWildcardMatch(key, id);
|
|
123
|
+
if (!match) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const mapped = getMappedTargetPath(target);
|
|
128
|
+
if (!mapped) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return resolve(pkg.root, mapped.replace("*", match));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return null;
|
|
136
|
+
};
|
|
2
137
|
|
|
3
138
|
export default defineConfig({
|
|
139
|
+
plugins: [
|
|
140
|
+
{
|
|
141
|
+
name: "interfere:package-imports",
|
|
142
|
+
enforce: "pre",
|
|
143
|
+
resolveId(id, importer) {
|
|
144
|
+
if (!id.startsWith("#")) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return resolveSubpathImport(id, importer) ?? null;
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
resolve: {
|
|
153
|
+
// Use @source condition so package exports resolve to .ts source files
|
|
154
|
+
// NOTE: `resolve.conditions` replaces Vite's defaults, so we keep the defaults and add `@source`.
|
|
155
|
+
// Default per Vite docs: ["module", "browser", "development|production"]
|
|
156
|
+
conditions: ["@source", "module", "browser", "development|production"],
|
|
157
|
+
},
|
|
4
158
|
test: {
|
|
5
159
|
environment: "node",
|
|
6
160
|
globals: true,
|
|
@@ -9,17 +163,28 @@ export default defineConfig({
|
|
|
9
163
|
sequence: {
|
|
10
164
|
concurrent: false,
|
|
11
165
|
},
|
|
166
|
+
exclude: [...configDefaults.exclude, "test/playwright/**"],
|
|
12
167
|
coverage: {
|
|
168
|
+
provider: "v8",
|
|
13
169
|
exclude: [
|
|
170
|
+
...(configDefaults.coverage?.exclude ?? []),
|
|
171
|
+
// Test files
|
|
172
|
+
"**/*.test.*",
|
|
173
|
+
"**/*.spec.*",
|
|
14
174
|
"__tests__/**",
|
|
15
|
-
|
|
16
|
-
"**/*.
|
|
175
|
+
// Config files
|
|
176
|
+
"**/*.config.*",
|
|
177
|
+
"env.ts",
|
|
178
|
+
"keys.ts",
|
|
179
|
+
// Type declarations
|
|
17
180
|
"**/*.d.ts",
|
|
18
|
-
|
|
181
|
+
// Build artifacts
|
|
19
182
|
"dist/**",
|
|
20
|
-
"node_modules/**",
|
|
21
|
-
".turbo/**",
|
|
22
183
|
"coverage/**",
|
|
184
|
+
".next/**",
|
|
185
|
+
".turbo/**",
|
|
186
|
+
// Next.js app boilerplate
|
|
187
|
+
"src/app/layout.tsx",
|
|
23
188
|
],
|
|
24
189
|
},
|
|
25
190
|
},
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interfere/vitest-config",
|
|
3
|
-
"version": "1.0.0",
|
|
3
|
+
"version": "1.0.1-alpha.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
6
|
+
"exports": {
|
|
7
|
+
"./library": "./library.ts"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"vitest": "^4.0.
|
|
10
|
+
"vitest": "^4.0.16"
|
|
11
11
|
},
|
|
12
12
|
"publishConfig": {
|
|
13
13
|
"access": "public"
|