85 lines
2.2 KiB
JavaScript
85 lines
2.2 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
import fs from "node:fs";
|
||
|
|
import path from "node:path";
|
||
|
|
import { pathToFileURL } from "node:url";
|
||
|
|
|
||
|
|
const root = process.cwd();
|
||
|
|
const pkgPath = path.join(root, "package.json");
|
||
|
|
|
||
|
|
if (!fs.existsSync(pkgPath)) {
|
||
|
|
console.error("verify-exports: package.json not found");
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
||
|
|
const exportsMap = pkg.exports ?? {};
|
||
|
|
|
||
|
|
const missing = [];
|
||
|
|
const importTargets = [];
|
||
|
|
const importFailures = [];
|
||
|
|
|
||
|
|
function collectTargets(subpath, target, fields = []) {
|
||
|
|
if (typeof target === "string") {
|
||
|
|
importTargets.push({ subpath, fields, target });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!target || typeof target !== "object") {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const [field, nestedTarget] of Object.entries(target)) {
|
||
|
|
collectTargets(subpath, nestedTarget, [...fields, field]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const [subpath, target] of Object.entries(exportsMap)) {
|
||
|
|
collectTargets(subpath, target);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const item of importTargets) {
|
||
|
|
const abs = path.join(root, item.target);
|
||
|
|
if (!fs.existsSync(abs)) {
|
||
|
|
missing.push({
|
||
|
|
subpath: item.subpath,
|
||
|
|
field: item.fields.join(".") || "default",
|
||
|
|
target: item.target,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (missing.length > 0) {
|
||
|
|
console.error("verify-exports: missing export targets:");
|
||
|
|
for (const item of missing) {
|
||
|
|
console.error(` - ${item.subpath} (${item.field}): ${item.target}`);
|
||
|
|
}
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const item of importTargets) {
|
||
|
|
const finalField = item.fields[item.fields.length - 1] ?? "default";
|
||
|
|
if (finalField !== "import" && !item.target.endsWith(".js") && !item.target.endsWith(".mjs")) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const abs = path.join(root, item.target);
|
||
|
|
await import(pathToFileURL(abs).href);
|
||
|
|
} catch (error) {
|
||
|
|
importFailures.push({
|
||
|
|
spec: `${item.subpath} (${item.fields.join(".") || "default"})`,
|
||
|
|
error: error instanceof Error ? error.message : String(error),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (importFailures.length > 0) {
|
||
|
|
console.error("verify-exports: export import smoke failed:");
|
||
|
|
for (const fail of importFailures) {
|
||
|
|
console.error(` - ${fail.spec}: ${fail.error}`);
|
||
|
|
}
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log("verify-exports: all export targets exist and import successfully");
|