@nestia/sdk
Version:
Nestia SDK and Swagger generator
166 lines • 8.16 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SdkGenerator = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const CloneGenerator_1 = require("./CloneGenerator");
const SdkDistributionComposer_1 = require("./internal/SdkDistributionComposer");
const SdkFileProgrammer_1 = require("./internal/SdkFileProgrammer");
const SdkHttpParameterProgrammer_1 = require("./internal/SdkHttpParameterProgrammer");
var SdkGenerator;
(function (SdkGenerator) {
SdkGenerator.generate = (app) => __awaiter(this, void 0, void 0, function* () {
if (app.project.config.output === undefined)
throw new Error("Output directory is not defined.");
// PREPARE NEW DIRECTORIES
console.log("Generating SDK Library");
yield fs_1.default.promises.mkdir(app.project.config.output, { recursive: true });
// BUNDLING
yield SdkGenerator.bundle(app.project.config.output);
// STRUCTURES
if (app.project.config.clone === true)
yield CloneGenerator_1.CloneGenerator.write(app);
// FUNCTIONAL
yield SdkFileProgrammer_1.SdkFileProgrammer.generate(app);
// DISTRIBUTION
if (app.project.config.distribute !== undefined)
yield SdkDistributionComposer_1.SdkDistributionComposer.compose({
config: app.project.config,
mcp: app.routes.some((r) => r.protocol === "mcp"),
websocket: app.routes.some((r) => r.protocol === "websocket"),
});
});
SdkGenerator.validate = (app) => {
const errors = [];
validateMcpDuplicates(errors)(app.routes);
validateMcpAccessors(errors)(app.routes);
if (app.project.config.clone === true)
return errors;
for (const route of app.routes)
if (route.protocol === "http")
validateImplicit({
config: app.project.config,
errors,
route,
});
return errors;
};
const validateMcpDuplicates = (errors) => (routes) => {
var _a;
const dict = new Map();
for (const route of routes)
if (route.protocol === "mcp") {
const array = (_a = dict.get(route.toolName)) !== null && _a !== void 0 ? _a : [];
array.push(route);
dict.set(route.toolName, array);
}
for (const [toolName, list] of dict)
if (list.length > 1)
for (const route of list)
errors.push({
file: route.controller.file,
class: route.controller.class.name,
function: route.function.name || route.name,
from: `@McpRoute(${JSON.stringify(toolName)})`,
contents: [
`Duplicate MCP tool name ${JSON.stringify(toolName)} is not allowed.`,
],
});
};
const validateMcpAccessors = (errors) => (routes) => {
var _a;
const dict = new Map();
for (const route of routes)
if (route.protocol === "mcp") {
const accessor = route.accessor.join(".");
const array = (_a = dict.get(accessor)) !== null && _a !== void 0 ? _a : [];
array.push(route);
dict.set(accessor, array);
}
for (const [accessor, list] of dict)
if (list.length > 1)
for (const route of list)
errors.push({
file: route.controller.file,
class: route.controller.class.name,
function: route.function.name || route.name,
from: `@McpRoute(${JSON.stringify(route.toolName)})`,
contents: [
`MCP tool name ${JSON.stringify(route.toolName)} conflicts on generated SDK accessor "api.functional.${accessor}".`,
],
});
};
const validateImplicit = (props) => {
for (const p of SdkHttpParameterProgrammer_1.SdkHttpParameterProgrammer.getAll(props.route)) {
if (isImplicitType(p.type))
props.errors.push({
file: props.route.controller.file,
class: props.route.controller.class.name,
function: props.route.name,
from: `parameter ${JSON.stringify(p.name)}`,
contents: [`implicit (unnamed) parameter type.`],
});
}
if (props.config.propagate === true)
for (const [key, value] of Object.entries(props.route.exceptions))
if (isImplicitType(value.type))
props.errors.push({
file: props.route.controller.file,
class: props.route.controller.class.name,
function: props.route.name,
from: `exception ${JSON.stringify(key)}`,
contents: [`implicit (unnamed) exception type.`],
});
if (props.route.success.binary === false &&
isImplicitType(props.route.success.type))
props.errors.push({
file: props.route.controller.file,
class: props.route.controller.class.name,
function: props.route.name,
from: "success",
contents: [`implicit (unnamed) return type.`],
});
};
const isImplicitType = (type) => { var _a; return type.name === "__type" ||
type.name === "__object" ||
type.name.startsWith("__type.") ||
type.name.startsWith("__object.") ||
type.name.includes("readonly [") ||
(!!((_a = type.typeArguments) === null || _a === void 0 ? void 0 : _a.length) && type.typeArguments.some(isImplicitType)); };
/**
* Emplace the static bundle files (`index.ts`, `module.ts`, ...) into the SDK
* output directory.
*
* Files the user already has are never touched, so that hand-written
* customizations (e.g. extra re-exports in `module.ts`) survive regeneration.
* Only missing files are filled in from the bundle.
*/
SdkGenerator.bundle = (output) => __awaiter(this, void 0, void 0, function* () {
const files = yield fs_1.default.promises.readdir(SdkGenerator.BUNDLE_PATH);
for (const file of files) {
const current = `${SdkGenerator.BUNDLE_PATH}/${file}`;
const target = `${output}/${file}`;
const stats = yield fs_1.default.promises.stat(current);
if (stats.isFile() === false)
continue;
if (fs_1.default.existsSync(target) === true)
continue;
const content = yield fs_1.default.promises.readFile(current, "utf8");
yield fs_1.default.promises.writeFile(target, content, "utf8");
}
});
SdkGenerator.BUNDLE_PATH = path_1.default.join(__dirname, "..", "..", "assets", "bundle", "api");
})(SdkGenerator || (exports.SdkGenerator = SdkGenerator = {}));
//# sourceMappingURL=SdkGenerator.js.map