@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.
Files changed (3) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/library.ts +171 -6
  3. package/package.json +4 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @interfere/vitest-config
2
+
3
+ ## 1.0.1-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [`477492c`](https://github.com/interfere-inc/repo/commit/477492c61dc69df8e270871b57483bd2bfcb7100) Thanks [@skve](https://github.com/skve)! - Progress
package/library.ts CHANGED
@@ -1,6 +1,160 @@
1
- import { defineConfig } from "vitest/config";
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
- "**/*.test.ts",
16
- "**/*.test.tsx",
175
+ // Config files
176
+ "**/*.config.*",
177
+ "env.ts",
178
+ "keys.ts",
179
+ // Type declarations
17
180
  "**/*.d.ts",
18
- "vitest.config.ts",
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
- "dependencies": {
7
- "@total-typescript/ts-reset": "^0.6.1"
6
+ "exports": {
7
+ "./library": "./library.ts"
8
8
  },
9
9
  "devDependencies": {
10
- "vitest": "^4.0.1"
10
+ "vitest": "^4.0.16"
11
11
  },
12
12
  "publishConfig": {
13
13
  "access": "public"