# 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 `operationId`s 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)` — prefers `displayName`, falls back to `name`. - `componentPrefix(plugin)` — `` literal, used by the emitter as the prefix for `components.schemas` entries. - `normaliseRoutePath(path)` — rewrites Express-style `:id` parameters into the OAS `{id}` form. Idempotent. - `operationIdFor(plugin, method, path)` — full deterministic id: `..`. - `assignOperationIds(inputs)` — bulk walk that respects pre-set `operationId` values and raises a typed error on collision. ## Usage: Basic ```ts 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 ```ts 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. `:443` in a server URL) are not rewritten. - Method is lower-cased to match OAS path-item key casing. - Pre-set `operationId` overrides 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.