Skip to content

Commit 5a4945f

Browse files
committed
Adopt #/ subpath imports (TS 6 feature)
- Add package.json imports field with source/default conditions to all library packages (core, browser, node, react) - Convert all relative imports in src/ and test/ files to #/ paths - Add paths mapping in each package's tsconfig.json for tsc resolution - Add --conditions=source to esbuild commands for source bundling - Replace jest-ts-webcompat-resolver with custom jest-resolver.cjs that supports package.json imports field per-package resolution and .js → .ts extension mapping
1 parent 79c2f8c commit 5a4945f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+357
-260
lines changed

jest-resolver.cjs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const path = require("path");
2+
const fs = require("fs");
3+
4+
/**
5+
* Custom jest resolver that handles:
6+
* 1. Package.json "imports" field (#/ subpath imports) — per-package resolution
7+
* 2. TypeScript .js → .ts extension mapping for ESM imports
8+
*
9+
* Replaces jest-ts-webcompat-resolver with full #/ import support.
10+
*/
11+
module.exports = (request, options) => {
12+
// Handle #/ subpath imports by reading the nearest package.json
13+
if (request.startsWith("#/")) {
14+
const packageRoot = findPackageRoot(options.basedir);
15+
if (packageRoot) {
16+
const pkgJson = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8"));
17+
if (pkgJson.imports) {
18+
const mapping = pkgJson.imports["#/*"];
19+
if (mapping) {
20+
const base = typeof mapping === "string" ? mapping : mapping.source || mapping.default;
21+
if (base) {
22+
const prefix = base.replace("*", "");
23+
const suffix = request.slice(2);
24+
const resolved = path.join(packageRoot, prefix, suffix);
25+
return resolveWithExtensions(resolved);
26+
}
27+
}
28+
}
29+
}
30+
}
31+
32+
// Handle .js → .ts extension mapping for TypeScript ESM imports
33+
if (request.endsWith(".js")) {
34+
const tsRequest = request.slice(0, -3) + ".ts";
35+
try {
36+
return options.defaultResolver(tsRequest, options);
37+
} catch {
38+
// Try .tsx
39+
}
40+
const tsxRequest = request.slice(0, -3) + ".tsx";
41+
try {
42+
return options.defaultResolver(tsxRequest, options);
43+
} catch {
44+
// Fall through to default
45+
}
46+
}
47+
48+
return options.defaultResolver(request, options);
49+
};
50+
51+
function findPackageRoot(dir) {
52+
let current = dir;
53+
while (current !== path.dirname(current)) {
54+
if (fs.existsSync(path.join(current, "package.json"))) {
55+
const pkg = path.join(current, "package.json");
56+
const content = JSON.parse(fs.readFileSync(pkg, "utf-8"));
57+
if (content.imports) {
58+
return current;
59+
}
60+
}
61+
current = path.dirname(current);
62+
}
63+
return null;
64+
}
65+
66+
function resolveWithExtensions(filePath) {
67+
const base = filePath.replace(/\.js$/, "");
68+
for (const ext of [".ts", ".tsx", ".js"]) {
69+
const fullPath = base + ext;
70+
if (fs.existsSync(fullPath)) {
71+
return fullPath;
72+
}
73+
}
74+
if (fs.existsSync(filePath)) {
75+
return filePath;
76+
}
77+
throw new Error(`Cannot resolve: ${filePath}`);
78+
}

package-lock.json

Lines changed: 0 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/browser/package.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
".": "./dist/index.js",
3333
"./package.json": "./package.json"
3434
},
35+
"imports": {
36+
"#/*": {
37+
"source": "./src/*",
38+
"default": "./dist/*"
39+
}
40+
},
3541
"jest": {
3642
"moduleFileExtensions": [
3743
"js",
@@ -40,7 +46,7 @@
4046
"moduleNameMapper": {
4147
"^@exceptionless/(.*)$": "<rootDir>/../$1/src"
4248
},
43-
"resolver": "jest-ts-webcompat-resolver",
49+
"resolver": "../../jest-resolver.cjs",
4450
"transform": {
4551
"^.+\\.tsx?$": [
4652
"ts-jest",
@@ -54,8 +60,8 @@
5460
"testEnvironment": "jsdom"
5561
},
5662
"scripts": {
57-
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --outfile=dist/index.bundle.min.js",
58-
"watch": "tsc -p ../core/tsconfig.json -w --preserveWatchOutput & tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --watch --outfile=dist/index.bundle.js",
63+
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
64+
"watch": "tsc -p ../core/tsconfig.json -w --preserveWatchOutput & tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --watch --outfile=dist/index.bundle.js",
5965
"test": "jest",
6066
"test:watch": "jest --watch"
6167
},
@@ -68,7 +74,6 @@
6874
"esbuild": "^0.27.4",
6975
"jest": "^30.3.0",
7076
"jest-environment-jsdom": "^30.3.0",
71-
"jest-ts-webcompat-resolver": "^1.0.1",
7277
"ts-jest": "^29.4.6"
7378
},
7479
"dependencies": {

packages/browser/src/BrowserExceptionlessClient.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Configuration, ExceptionlessClient, SimpleErrorPlugin } from "@exceptionless/core";
22

3-
import { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js";
4-
import { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
5-
import { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js";
6-
import { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
7-
import { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js";
8-
import { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js";
3+
import { BrowserErrorPlugin } from "#/plugins/BrowserErrorPlugin.js";
4+
import { BrowserGlobalHandlerPlugin } from "#/plugins/BrowserGlobalHandlerPlugin.js";
5+
import { BrowserIgnoreExtensionErrorsPlugin } from "#/plugins/BrowserIgnoreExtensionErrorsPlugin.js";
6+
import { BrowserLifeCyclePlugin } from "#/plugins/BrowserLifeCyclePlugin.js";
7+
import { BrowserModuleInfoPlugin } from "#/plugins/BrowserModuleInfoPlugin.js";
8+
import { BrowserRequestInfoPlugin } from "#/plugins/BrowserRequestInfoPlugin.js";
99

1010
export class BrowserExceptionlessClient extends ExceptionlessClient {
1111
public async startup(configurationOrApiKey?: (config: Configuration) => void | string): Promise<void> {

packages/browser/src/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
export * from "@exceptionless/core";
22

3-
export { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js";
4-
export { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
5-
export { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js";
6-
export { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
7-
export { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js";
8-
export { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js";
9-
export { BrowserExceptionlessClient } from "./BrowserExceptionlessClient.js";
3+
export { BrowserErrorPlugin } from "#/plugins/BrowserErrorPlugin.js";
4+
export { BrowserGlobalHandlerPlugin } from "#/plugins/BrowserGlobalHandlerPlugin.js";
5+
export { BrowserIgnoreExtensionErrorsPlugin } from "#/plugins/BrowserIgnoreExtensionErrorsPlugin.js";
6+
export { BrowserLifeCyclePlugin } from "#/plugins/BrowserLifeCyclePlugin.js";
7+
export { BrowserModuleInfoPlugin } from "#/plugins/BrowserModuleInfoPlugin.js";
8+
export { BrowserRequestInfoPlugin } from "#/plugins/BrowserRequestInfoPlugin.js";
9+
export { BrowserExceptionlessClient } from "#/BrowserExceptionlessClient.js";
1010

11-
import { BrowserExceptionlessClient } from "./BrowserExceptionlessClient.js";
11+
import { BrowserExceptionlessClient } from "#/BrowserExceptionlessClient.js";
1212
export const Exceptionless = new BrowserExceptionlessClient();

packages/browser/test/plugins/BrowserErrorPlugin.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { expect } from "expect";
44
import { ErrorInfo, Event, EventContext, EventPluginContext, ExceptionlessClient, KnownEventDataKeys } from "@exceptionless/core";
55

66
import { CapturedExceptions } from "./../../../core/test/plugins/default/exceptions.js";
7-
import { BrowserErrorPlugin } from "../../src/plugins/BrowserErrorPlugin.js";
7+
import { BrowserErrorPlugin } from "#/plugins/BrowserErrorPlugin.js";
88

99
class BaseTestError extends Error {
1010
public name = "NotImplementedError";

packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { expect } from "expect";
33

44
import { EventContext, EventPluginContext, ExceptionlessClient } from "@exceptionless/core";
55

6-
import { BrowserIgnoreExtensionErrorsPlugin } from "../../src/plugins/BrowserIgnoreExtensionErrorsPlugin.js";
6+
import { BrowserIgnoreExtensionErrorsPlugin } from "#/plugins/BrowserIgnoreExtensionErrorsPlugin.js";
77

88
describe("BrowserIgnoreExtensionErrorsPlugin", () => {
99
let client: ExceptionlessClient;

packages/browser/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"compilerOptions": {
44
"lib": ["DOM", "ES2022"],
55
"outDir": "dist",
6+
"paths": {
7+
"#/*": ["./src/*"]
8+
},
69
"rootDir": "src",
710
"types": ["jest"]
811
},

packages/core/package.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,22 @@
3232
".": "./dist/index.js",
3333
"./package.json": "./package.json"
3434
},
35+
"imports": {
36+
"#/*": {
37+
"source": "./src/*",
38+
"default": "./dist/*"
39+
}
40+
},
3541
"jest": {
3642
"moduleFileExtensions": [
3743
"js",
3844
"ts"
3945
],
4046
"moduleNameMapper": {
47+
"^#/(.*)$": "<rootDir>/src/$1",
4148
"^@exceptionless/(.*)$": "<rootDir>/../$1/src"
4249
},
43-
"resolver": "jest-ts-webcompat-resolver",
50+
"resolver": "../../jest-resolver.cjs",
4451
"transform": {
4552
"^.+\\.tsx?$": [
4653
"ts-jest",
@@ -54,8 +61,8 @@
5461
"testEnvironment": "jsdom"
5562
},
5663
"scripts": {
57-
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --outfile=dist/index.bundle.min.js",
58-
"watch": "tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --watch --outfile=dist/index.bundle.js",
64+
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.js && esbuild src/index.ts --bundle --minify --sourcemap --target=es2022 --format=esm --conditions=source --outfile=dist/index.bundle.min.js",
65+
"watch": "tsc -p tsconfig.json -w --preserveWatchOutput & esbuild src/index.ts --bundle --sourcemap --target=es2022 --format=esm --conditions=source --watch --outfile=dist/index.bundle.js",
5966
"test": "jest",
6067
"test:watch": "jest --watch"
6168
},
@@ -68,7 +75,6 @@
6875
"esbuild": "^0.27.4",
6976
"jest": "^30.3.0",
7077
"jest-environment-jsdom": "^30.3.0",
71-
"jest-ts-webcompat-resolver": "^1.0.1",
7278
"ts-jest": "^29.4.6"
7379
}
7480
}

packages/core/src/EventBuilder.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { ExceptionlessClient } from "./ExceptionlessClient.js";
2-
import { Event, EventType, KnownEventDataKeys } from "./models/Event.js";
3-
import { ManualStackingInfo } from "./models/data/ManualStackingInfo.js";
4-
import { UserInfo } from "./models/data/UserInfo.js";
5-
import { EventContext } from "./models/EventContext.js";
6-
import { isEmpty, stringify } from "./Utils.js";
7-
import { EventPluginContext } from "./plugins/EventPluginContext.js";
1+
import { ExceptionlessClient } from "#/ExceptionlessClient.js";
2+
import { Event, EventType, KnownEventDataKeys } from "#/models/Event.js";
3+
import { ManualStackingInfo } from "#/models/data/ManualStackingInfo.js";
4+
import { UserInfo } from "#/models/data/UserInfo.js";
5+
import { EventContext } from "#/models/EventContext.js";
6+
import { isEmpty, stringify } from "#/Utils.js";
7+
import { EventPluginContext } from "#/plugins/EventPluginContext.js";
88

99
export class EventBuilder {
1010
public target: Event;

0 commit comments

Comments
 (0)