Skip to content

Commit b462d7e

Browse files
niemyjskiclaude
andcommitted
Add resolve-package-imports build step and update Next.js example
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 784e7e9 commit b462d7e

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import path from "path";
2+
import { describe, expect, test } from "vitest";
3+
4+
import { rewritePackageImportSpecifiers } from "../../../scripts/resolve-package-imports.mjs";
5+
6+
describe("rewritePackageImportSpecifiers", () => {
7+
test("should rewrite top-level package imports to relative paths", () => {
8+
const filePath = path.resolve("packages/core/dist/index.js");
9+
const distDir = path.resolve("packages/core/dist");
10+
11+
const result = rewritePackageImportSpecifiers('export { Configuration } from "#/configuration/Configuration.js";\n', filePath, distDir);
12+
13+
expect(result).toBe('export { Configuration } from "./configuration/Configuration.js";\n');
14+
});
15+
16+
test("should rewrite nested package imports to relative paths", () => {
17+
const filePath = path.resolve("packages/core/dist/submission/DefaultSubmissionClient.js");
18+
const distDir = path.resolve("packages/core/dist");
19+
20+
const result = rewritePackageImportSpecifiers('import { SettingsManager } from "#/configuration/SettingsManager.js";\n', filePath, distDir);
21+
22+
expect(result).toBe('import { SettingsManager } from "../configuration/SettingsManager.js";\n');
23+
});
24+
25+
test("should rewrite dynamic imports to relative paths", () => {
26+
const filePath = path.resolve("packages/core/dist/index.js");
27+
const distDir = path.resolve("packages/core/dist");
28+
29+
const result = rewritePackageImportSpecifiers('const module = await import("#/plugins/default/HeartbeatPlugin.js");\n', filePath, distDir);
30+
31+
expect(result).toBe('const module = await import("./plugins/default/HeartbeatPlugin.js");\n');
32+
});
33+
});
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import path from "node:path";
2+
import { readdir, readFile, stat, writeFile } from "node:fs/promises";
3+
import { fileURLToPath } from "node:url";
4+
5+
const PACKAGE_IMPORT_PREFIX = "#/";
6+
const FILE_PATTERN = /\.(?:js|d\.ts)$/;
7+
8+
export function rewritePackageImportSpecifiers(source, filePath, distDir) {
9+
const rewrite = (match, prefix, specifier, suffix) => `${prefix}${toRelativeSpecifier(filePath, distDir, specifier)}${suffix}`;
10+
11+
return source
12+
.replace(/(from\s+["'])#\/([^"']+)(["'])/g, rewrite)
13+
.replace(/(import\(\s*["'])#\/([^"']+)(["']\s*\))/g, rewrite);
14+
}
15+
16+
export async function rewritePackageDistImports(packageDir) {
17+
const distDir = path.join(packageDir, "dist");
18+
const files = await collectFiles(distDir);
19+
20+
await Promise.all(
21+
files.map(async (filePath) => {
22+
if (!FILE_PATTERN.test(filePath)) {
23+
return;
24+
}
25+
26+
const source = await readFile(filePath, "utf8");
27+
const rewritten = rewritePackageImportSpecifiers(source, filePath, distDir);
28+
29+
if (rewritten !== source) {
30+
await writeFile(filePath, rewritten, "utf8");
31+
}
32+
})
33+
);
34+
}
35+
36+
async function collectFiles(directory) {
37+
const entries = await readdir(directory, { withFileTypes: true });
38+
const files = [];
39+
40+
for (const entry of entries) {
41+
const entryPath = path.join(directory, entry.name);
42+
43+
if (entry.isDirectory()) {
44+
files.push(...(await collectFiles(entryPath)));
45+
continue;
46+
}
47+
48+
if (entry.isFile()) {
49+
files.push(entryPath);
50+
}
51+
}
52+
53+
return files;
54+
}
55+
56+
function toRelativeSpecifier(filePath, distDir, specifier) {
57+
const targetPath = path.join(distDir, specifier);
58+
let relativePath = path.relative(path.dirname(filePath), targetPath).replaceAll(path.sep, "/");
59+
60+
if (!relativePath.startsWith(".")) {
61+
relativePath = `./${relativePath}`;
62+
}
63+
64+
return relativePath;
65+
}
66+
67+
async function main() {
68+
const requestedDirectory = process.argv[2] ? path.resolve(process.cwd(), process.argv[2]) : process.cwd();
69+
const distDirectory = path.join(requestedDirectory, "dist");
70+
const distStats = await stat(distDirectory).catch(() => null);
71+
72+
if (!distStats?.isDirectory()) {
73+
throw new Error(`Expected a dist directory in ${requestedDirectory}`);
74+
}
75+
76+
await rewritePackageDistImports(requestedDirectory);
77+
}
78+
79+
const currentFilePath = fileURLToPath(import.meta.url);
80+
81+
if (process.argv[1] && path.resolve(process.argv[1]) === currentFilePath) {
82+
await main();
83+
}

0 commit comments

Comments
 (0)