Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
69 lines
2.0 KiB
JavaScript
69 lines
2.0 KiB
JavaScript
import { dirname, resolve } from "node:path";
|
|
|
|
export function normalizeOpenApiFragmentRefs(value, extensionKey) {
|
|
if (value == null) {
|
|
return [];
|
|
}
|
|
if (!Array.isArray(value)) {
|
|
throw new Error(`${extensionKey} must be an array`);
|
|
}
|
|
return value.map((entry) => normalizeOpenApiFragmentRef(entry, extensionKey));
|
|
}
|
|
|
|
export function resolveOpenApiFragmentPath(
|
|
fragmentRef,
|
|
{ repoRoot, specPath, resolvePackageSpecifier }
|
|
) {
|
|
if (typeof fragmentRef === "string") {
|
|
if (fragmentRef.startsWith(".")) {
|
|
return resolve(dirname(specPath), fragmentRef);
|
|
}
|
|
return resolve(repoRoot, fragmentRef);
|
|
}
|
|
|
|
const specifier = `${fragmentRef.package}/${fragmentRef.path}`;
|
|
try {
|
|
return resolvePackageSpecifier(specifier);
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Cannot resolve OpenAPI fragment ${specifier}; install an exact released package version before generation`,
|
|
{ cause: error }
|
|
);
|
|
}
|
|
}
|
|
|
|
function normalizeOpenApiFragmentRef(entry, extensionKey) {
|
|
if (typeof entry === "string") {
|
|
const value = entry.trim();
|
|
if (value === "") {
|
|
throw new Error(`${extensionKey} cannot contain empty entries`);
|
|
}
|
|
return value;
|
|
}
|
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
throw new Error(
|
|
`${extensionKey} entries must be paths or package/path objects`
|
|
);
|
|
}
|
|
const packageName = String(entry.package ?? "").trim();
|
|
const packagePath = String(entry.path ?? "").trim();
|
|
const keys = Object.keys(entry);
|
|
if (
|
|
packageName === "" ||
|
|
packagePath === "" ||
|
|
keys.some((key) => key !== "package" && key !== "path")
|
|
) {
|
|
throw new Error(
|
|
`${extensionKey} package entries require only non-empty package and path fields`
|
|
);
|
|
}
|
|
const packagePathSegments = packagePath.split(/[\\/]/u);
|
|
if (
|
|
packagePath.startsWith("/") ||
|
|
packagePathSegments.some((segment) => segment === "." || segment === "..")
|
|
) {
|
|
throw new Error(`${extensionKey} package paths must be package-relative`);
|
|
}
|
|
return { package: packageName, path: packagePath };
|
|
}
|