3.1 KiB
3.1 KiB
namespacing
(no submodules)
Purpose
The namespacing module turns a plugin's structural identity (name,
displayName) plus a registered route's (method, path) tuple into the
deterministic OpenAPI surface fields — tag name, component-schema
prefix, normalised OAS path, and operationId. It is the bridge between
the plugin-namespaced runtime and the single merged OpenAPI 3.1
document @suaveplan/api-openapi emits.
Determinism matters: clients regenerate SDKs against the document and
expect stable operationIds across boots. Collisions — two plugins
producing the same id — would silently overwrite the earlier route in
client toolchains, so the module raises OPENAPI.OPERATION_ID_COLLISION
the moment a duplicate appears.
Features
tagFor(plugin)— prefersdisplayName, falls back toname.componentPrefix(plugin)—<pluginName>literal, used by the emitter as the prefix forcomponents.schemasentries.normaliseRoutePath(path)— rewrites Express-style:idparameters into the OAS{id}form. Idempotent.operationIdFor(plugin, method, path)— full deterministic id:<plugin>.<method>.<oasPath>.assignOperationIds(inputs)— bulk walk that respects pre-setoperationIdvalues and raises a typed error on collision.
Usage: Basic
import {
assignOperationIds,
operationIdFor,
tagFor,
} from "@suaveplan/api-openapi/namespacing";
const plugin = { name: "billing", displayName: "Billing" };
operationIdFor(plugin, "GET", "/invoices/:id");
// => "billing.get./invoices/{id}"
tagFor(plugin); // => "Billing"
Usage: Advanced
import { assignOperationIds } from "@suaveplan/api-openapi/namespacing";
import type { RegisteredRoute } from "@suaveplan/api-openapi/types";
const plugins = [
{ name: "billing", displayName: "Billing" },
{ name: "users" },
];
const routes: ReadonlyArray<{
plugin: (typeof plugins)[number];
route: RegisteredRoute;
}> = [
{ plugin: plugins[0]!, route: { method: "GET", path: "/invoices/:id", tags: [] } },
{ plugin: plugins[1]!, route: { method: "GET", path: "/users/:id", tags: [] } },
];
const namespaced = assignOperationIds(routes);
// Throws OPENAPI.OPERATION_ID_COLLISION if any duplicate appears.
API Reference
NamespacePluginInfo—{ name, displayName? }.tagFor(plugin) → string.componentPrefix(plugin) → string.normaliseRoutePath(path: string) → string.operationIdFor(plugin, method, path) → string.assignOperationIds(inputs) → NamespacedRoute[].NamespacedRoute—{ pluginName, tag, operationId, method, path, route }.
Implementation Notes
- Path normalisation uses the regex
:([A-Za-z_][\w-]*)so colons preceded by non-identifier characters (e.g.:443in a server URL) are not rewritten. - Method is lower-cased to match OAS path-item key casing.
- Pre-set
operationIdoverrides the derived one — useful for stable ids that pre-date the convention. Collisions still raise. - The module does not know about strictness; the emitter applies strictness to missing schemas separately.