@nestia/sdk
Version:
Nestia SDK and Swagger generator
106 lines (98 loc) • 3.84 kB
text/typescript
import {
HOST_METADATA,
PATH_METADATA,
SCOPE_OPTIONS_METADATA,
} from "@nestjs/common/constants";
import { INestiaProject } from "../structures/INestiaProject";
import { INestiaSdkInput } from "../structures/INestiaSdkInput";
import { IReflectController } from "../structures/IReflectController";
import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
import { IOperationMetadata } from "../transformers/IOperationMetadata";
import { ArrayUtil } from "../utils/ArrayUtil";
import { ReflectHttpOperationAnalyzer } from "./ReflectHttpOperationAnalyzer";
import { ReflectMetadataAnalyzer } from "./ReflectMetadataAnalyzer";
import { ReflectWebSocketOperationAnalyzer } from "./ReflectWebSocketOperationAnalyzer";
export namespace ReflectControllerAnalyzer {
export interface IProps {
project: Omit<INestiaProject, "config">;
controller: INestiaSdkInput.IController;
unique: WeakSet<Function>;
}
/* ---------------------------------------------------------
CONTROLLER
--------------------------------------------------------- */
export const analyze = (props: IProps): IReflectController | null => {
// MUST BE TYPE OF A CREATOR WHO HAS THE CONSTRUCTOR
if (
ArrayUtil.has(
Reflect.getMetadataKeys(props.controller.class),
PATH_METADATA,
HOST_METADATA,
SCOPE_OPTIONS_METADATA,
) === false
)
return null;
// BASIC INFO
const controller: IReflectController = {
class: props.controller.class,
file: props.controller.location,
operations: [],
prefixes: props.controller.prefixes,
paths: ReflectMetadataAnalyzer.paths(props.controller.class).filter(
(str) => {
if (str.includes("*") === true) {
props.project.warnings.push({
file: props.controller.location,
class: props.controller.class.name,
function: null,
from: null,
contents: ["@nestia/sdk does not compose wildcard controller."],
});
return false;
}
return true;
},
),
versions: ReflectMetadataAnalyzer.versions(props.controller.class),
security: ReflectMetadataAnalyzer.securities(props.controller.class),
tags:
Reflect.getMetadata("swagger/apiUseTags", props.controller.class) ?? [],
};
// OPERATORS
for (const [key, value] of _Get_prototype_entries(props.controller.class)) {
if (typeof value !== "function") continue;
const metadata: IOperationMetadata | undefined = Reflect.getMetadata(
"nestia/OperationMetadata",
props.controller.class.prototype,
key,
);
if (metadata === undefined) continue;
else if (metadata.jsDocTags.some((tag) => tag.name === "ignore"))
continue;
const next: ReflectHttpOperationAnalyzer.IProps = {
project: props.project,
controller: controller,
name: key,
function: value,
metadata,
};
const child: IReflectHttpOperation | IReflectWebSocketOperation | null =
ReflectWebSocketOperationAnalyzer.analyze(next) ??
ReflectHttpOperationAnalyzer.analyze(next);
if (child !== null) controller.operations.push(child);
}
return controller;
};
function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
const keyList = Object.getOwnPropertyNames(creator.prototype);
const entries: Array<[string, unknown]> = keyList.map((key) => [
key,
creator.prototype[key],
]);
const parent = Object.getPrototypeOf(creator);
if (parent.prototype !== undefined)
entries.push(..._Get_prototype_entries(parent));
return entries;
}
}