@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
118 lines (109 loc) • 4.02 kB
text/typescript
import { IHttpMigrateRoute } from "../../structures/IHttpMigrateRoute";
import { EndpointUtil } from "../../utils/EndpointUtil";
import { Escaper } from "../../utils/Escaper";
import { MapUtil } from "../../utils/MapUtil";
export namespace HttpMigrateRouteAccessor {
export const overwrite = (routes: IHttpMigrateRoute[]): void => {
const predefined: Map<string, number> = getPredefinedAccessors(routes);
const dict: Map<string, IElement> = collect((op) =>
op.emendedPath
.split("/")
.filter((str) => !!str.length && str[0] !== ":")
.map(EndpointUtil.normalize)
.map((str) => (Escaper.variable(str) ? str : `_${str}`)),
)(routes) as Map<string, IElement>;
for (const props of dict.values())
props.entries.forEach((entry, i) => {
entry.alias = EndpointUtil.escapeDuplicate(
[
...props.children,
...props.entries.filter((_, j) => i !== j).map((e) => e.alias),
].map(EndpointUtil.normalize),
)(EndpointUtil.normalize(entry.alias));
const parameters: { name: string; key: string }[] = [
...entry.route.parameters,
...(entry.route.body ? [entry.route.body] : []),
...(entry.route.headers ? [entry.route.headers] : []),
...(entry.route.query ? [entry.route.query] : []),
];
parameters.forEach(
(p, i) =>
(p.key = EndpointUtil.escapeDuplicate([
"connection",
entry.alias,
...parameters.filter((_, j) => i !== j).map((y) => y.key),
])(p.key)),
);
const accessor: string[] | undefined =
entry.route.operation()["x-samchon-accessor"];
if (accessor !== undefined && predefined.get(accessor.join(".")) === 1)
entry.route.accessor = accessor;
else entry.route.accessor = [...props.namespace, entry.alias];
});
};
const collect =
(getter: (r: IHttpMigrateRoute) => string[]) =>
(routes: IHttpMigrateRoute[]): Map<string, IElement> => {
const dict: Map<string, IElement> = new Map();
for (const r of routes) {
const namespace: string[] = getter(r);
let last: IElement = MapUtil.take(dict)(namespace.join("."))(() => ({
namespace,
children: new Set(),
entries: [],
}));
last.entries.push({
route: r,
alias: getName(r),
});
namespace.slice(0, -1).forEach((_i, i, array) => {
const partial: string[] = namespace.slice(0, array.length - i);
const element: IElement = MapUtil.take(dict)(partial.join("."))(
() => ({
namespace: partial,
children: new Set(),
entries: [],
}),
);
element.children.add(last.namespace.at(-1)!);
});
const top = MapUtil.take(dict)("")(() => ({
namespace: [],
children: new Set(),
entries: [],
}));
if (namespace.length) top.children.add(namespace[0]);
}
return dict;
};
const getName = (op: IHttpMigrateRoute): string => {
const method = op.method === "delete" ? "erase" : op.method;
if (op.parameters.length === 0) return method;
return (
method +
"By" +
op.parameters.map((p) => EndpointUtil.capitalize(p.key)).join("And")
);
};
const getPredefinedAccessors = (
routes: IHttpMigrateRoute[],
): Map<string, number> => {
const dict: Map<string, number> = new Map();
for (const r of routes) {
const accessor = r.operation()["x-samchon-accessor"]?.join(".");
if (accessor === undefined) continue;
else if (dict.has(accessor)) dict.set(accessor, dict.get(accessor)! + 1);
else dict.set(accessor, 1);
}
return dict;
};
interface IElement {
namespace: string[];
entries: IEntry[];
children: Set<string>;
}
interface IEntry {
route: IHttpMigrateRoute;
alias: string;
}
}