Files
tutti/tools/scripts/openapi-fragments.mjs
agent-radar 2ed3415fb7
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
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

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 };
}