Skip to content

Commit 431f1ef

Browse files
committed
fix: expose documented TypeScript package subpaths
The TypeScript docs reference package subpaths that were not present in the export map, so consumers following those examples could not rely on package-level resolution for metrics, models, kebab-case test cases, or evaluate helpers. Constraint: Keep the change additive and limited to documented TypeScript entrypoints. Rejected: Renaming or removing the existing testCase subpath | It may already be used by package consumers. Confidence: high Scope-risk: narrow Directive: Keep future public TypeScript subpaths covered by package export smoke tests. Tested: cd typescript && npm test -- package-exports.test.ts; cd typescript && npm run test:package-exports; cd typescript && npm run lint; git diff --check origin/main...HEAD Not-tested: Full cd typescript && npm test -- --runInBand passes locally | existing suite requires missing OPENAI_API_KEY and CONFIDENT_API_KEY, has an optional OpenAI Agents MCP dependency resolution failure, and includes an existing bad import in test/test-core/evaluate.test.ts.
1 parent 8ebfa33 commit 431f1ef

4 files changed

Lines changed: 158 additions & 0 deletions

File tree

.github/workflows/typescript_test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@ jobs:
3434
CONFIDENT_API_KEY: ${{ secrets.CONFIDENT_API_KEY }}
3535
CONFIDENT_TRACE_VERBOSE: 0
3636
run: npm test
37+
38+
- name: Validate package exports
39+
run: npm run test:package-exports

typescript/package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,31 @@
2323
"require": "./dist/dataset/index.js",
2424
"types": "./dist/dataset/index.d.ts"
2525
},
26+
"./metrics": {
27+
"import": "./dist/metrics/index.js",
28+
"require": "./dist/metrics/index.js",
29+
"types": "./dist/metrics/index.d.ts"
30+
},
31+
"./models": {
32+
"import": "./dist/models/index.js",
33+
"require": "./dist/models/index.js",
34+
"types": "./dist/models/index.d.ts"
35+
},
2636
"./testCase": {
2737
"import": "./dist/test-case/index.js",
2838
"require": "./dist/test-case/index.js",
2939
"types": "./dist/test-case/index.d.ts"
3040
},
41+
"./test-case": {
42+
"import": "./dist/test-case/index.js",
43+
"require": "./dist/test-case/index.js",
44+
"types": "./dist/test-case/index.d.ts"
45+
},
46+
"./evaluate": {
47+
"import": "./dist/evaluate/index.js",
48+
"require": "./dist/evaluate/index.js",
49+
"types": "./dist/evaluate/index.d.ts"
50+
},
3151
"./tracing": {
3252
"import": "./dist/tracing/index.js",
3353
"require": "./dist/tracing/index.js",
@@ -72,9 +92,21 @@
7292
"dataset": [
7393
"dist/dataset/index.d.ts"
7494
],
95+
"metrics": [
96+
"dist/metrics/index.d.ts"
97+
],
98+
"models": [
99+
"dist/models/index.d.ts"
100+
],
75101
"testCase": [
76102
"dist/test-case/index.d.ts"
77103
],
104+
"test-case": [
105+
"dist/test-case/index.d.ts"
106+
],
107+
"evaluate": [
108+
"dist/evaluate/index.d.ts"
109+
],
78110
"tracing": [
79111
"dist/tracing/index.d.ts"
80112
],
@@ -107,6 +139,7 @@
107139
"scripts": {
108140
"build": "tsc",
109141
"test": "jest",
142+
"test:package-exports": "npm run build && node test/test-core/package-exports-smoke.cjs",
110143
"lint": "eslint",
111144
"lint:fix": "eslint --fix"
112145
},
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const fs = require("fs");
2+
const path = require("path");
3+
4+
const packageRoot = path.resolve(__dirname, "../..");
5+
const packageJson = require(path.join(packageRoot, "package.json"));
6+
7+
const packageSubpaths = [
8+
{ exportKey: "./metrics", specifier: "deepeval/metrics" },
9+
{ exportKey: "./models", specifier: "deepeval/models" },
10+
{ exportKey: "./test-case", specifier: "deepeval/test-case" },
11+
{ exportKey: "./evaluate", specifier: "deepeval/evaluate" },
12+
{ exportKey: "./testCase", specifier: "deepeval/testCase" },
13+
];
14+
15+
function assert(condition, message) {
16+
if (!condition) {
17+
throw new Error(message);
18+
}
19+
}
20+
21+
function assertExportFilesExist(exportKey) {
22+
const exportEntry = packageJson.exports[exportKey];
23+
assert(exportEntry, `Missing package export ${exportKey}`);
24+
25+
for (const field of ["import", "require", "types"]) {
26+
const relativePath = exportEntry[field];
27+
assert(
28+
fs.existsSync(path.resolve(packageRoot, relativePath)),
29+
`Missing ${field} file for ${exportKey}: ${relativePath}`,
30+
);
31+
}
32+
}
33+
34+
async function main() {
35+
for (const { exportKey, specifier } of packageSubpaths) {
36+
assertExportFilesExist(exportKey);
37+
38+
require.resolve(specifier, { paths: [packageRoot] });
39+
require(specifier);
40+
await import(specifier);
41+
}
42+
}
43+
44+
main().catch((error) => {
45+
console.error(error);
46+
process.exitCode = 1;
47+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
4+
type PackageJson = {
5+
exports: Record<
6+
string,
7+
{
8+
import: string;
9+
require: string;
10+
types: string;
11+
}
12+
>;
13+
typesVersions: Record<string, Record<string, string[]>>;
14+
};
15+
16+
const packageRoot = path.resolve(__dirname, "../..");
17+
const packageJsonPath = path.join(packageRoot, "package.json");
18+
const packageJson = JSON.parse(
19+
fs.readFileSync(packageJsonPath, "utf8"),
20+
) as PackageJson;
21+
22+
const documentedSubpaths = [
23+
{
24+
subpath: "./metrics",
25+
sourceIndex: "src/metrics/index.ts",
26+
distIndex: "dist/metrics/index",
27+
},
28+
{
29+
subpath: "./models",
30+
sourceIndex: "src/models/index.ts",
31+
distIndex: "dist/models/index",
32+
},
33+
{
34+
subpath: "./test-case",
35+
sourceIndex: "src/test-case/index.ts",
36+
distIndex: "dist/test-case/index",
37+
},
38+
{
39+
subpath: "./evaluate",
40+
sourceIndex: "src/evaluate/index.ts",
41+
distIndex: "dist/evaluate/index",
42+
},
43+
];
44+
45+
describe("package exports", () => {
46+
test.each(documentedSubpaths)(
47+
"exports documented $subpath entrypoint",
48+
({ subpath, sourceIndex, distIndex }) => {
49+
const entry = packageJson.exports[subpath];
50+
expect(entry).toEqual({
51+
import: `./${distIndex}.js`,
52+
require: `./${distIndex}.js`,
53+
types: `./${distIndex}.d.ts`,
54+
});
55+
56+
expect(fs.existsSync(path.join(packageRoot, sourceIndex))).toBe(true);
57+
58+
const typesVersionPath = subpath.replace(/^\.\//, "");
59+
expect(packageJson.typesVersions["*"][typesVersionPath]).toEqual([
60+
`${distIndex}.d.ts`,
61+
]);
62+
},
63+
);
64+
65+
test("keeps the legacy camelCase testCase subpath available", () => {
66+
expect(packageJson.exports["./testCase"]).toEqual({
67+
import: "./dist/test-case/index.js",
68+
require: "./dist/test-case/index.js",
69+
types: "./dist/test-case/index.d.ts",
70+
});
71+
expect(packageJson.typesVersions["*"].testCase).toEqual([
72+
"dist/test-case/index.d.ts",
73+
]);
74+
});
75+
});

0 commit comments

Comments
 (0)