node-apis
Version:
š Advanced TypeScript API generator with clean architecture, comprehensive testing, and automatic formatting. Generate production-ready Node.js APIs with complete integration test suites.
234 lines (232 loc) ⢠9.33 kB
JavaScript
;
/**
* Module generation service - Main business logic
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateModuleStructurePhase2 = exports.generateModuleStructurePhase1 = exports.generateModuleStructure = void 0;
const module_name_validator_1 = require("../validators/module-name.validator");
const path_utils_1 = require("../filesystem/path.utils");
const directory_operations_1 = require("../filesystem/directory.operations");
const file_generator_service_1 = require("./file-generator.service");
const path = __importStar(require("path"));
/**
* Generates the API module folder structure
*/
const generateModuleStructure = async ({ moduleName, options = {}, apiType, }) => {
const { baseDir = process.cwd(), force = false, appendMode = false, targetDir } = options;
try {
// Validate the module name with enhanced naming
const validation = (0, module_name_validator_1.validateModuleName)({ name: moduleName });
if (!validation.isValid) {
return {
success: false,
error: validation.error,
};
}
const normalizedName = validation.normalizedName;
const modulePath = await (0, path_utils_1.getModulePath)({
moduleName: normalizedName,
baseDir,
...(targetDir && { targetDir }),
});
// Check if directory already exists
const exists = await (0, directory_operations_1.directoryExists)({ dirPath: modulePath });
if (exists && !force && !appendMode) {
return {
success: false,
error: `Module directory already exists: ${modulePath}\nUse --force flag to overwrite or run in interactive mode to append.`,
};
}
// Create the main module directory
await (0, directory_operations_1.ensureDirectory)({ dirPath: modulePath });
// Create all subdirectories based on API type
const subdirectories = (0, path_utils_1.getModuleSubdirectories)(apiType, false, apiType?.framework);
const createdDirs = await (0, directory_operations_1.createDirectories)({
basePath: modulePath,
subdirectories,
});
// Generate TypeScript files if apiType is provided
let generatedFiles = [];
if (apiType) {
generatedFiles = await (0, file_generator_service_1.generateApiFiles)({
moduleName: normalizedName,
modulePath,
apiType,
appendMode,
});
}
// Format success message
const message = formatSuccessMessage({
moduleName: normalizedName,
modulePath,
...(apiType && { apiType }),
});
return {
success: true,
moduleName: normalizedName,
modulePath,
createdDirectories: createdDirs,
generatedFiles,
message,
};
}
catch (error) {
return await handleGenerationError(error, moduleName, baseDir);
}
};
exports.generateModuleStructure = generateModuleStructure;
/**
* Phase 1: Creates only the main module directory and types subdirectory
* Used for two-phase generation where we want to generate types first
*/
const generateModuleStructurePhase1 = async ({ moduleName, options = {}, framework, }) => {
const { baseDir = process.cwd(), force = false, appendMode = false, targetDir } = options;
try {
// Validate the module name with enhanced naming
const validation = (0, module_name_validator_1.validateModuleName)({ name: moduleName });
if (!validation.isValid) {
return {
success: false,
error: validation.error,
};
}
const normalizedName = validation.normalizedName;
const modulePath = await (0, path_utils_1.getModulePath)({
moduleName: normalizedName,
baseDir,
...(framework && { framework }),
...(targetDir && { targetDir }),
});
// Check if directory already exists
const exists = await (0, directory_operations_1.directoryExists)({ dirPath: modulePath });
if (exists && !force && !appendMode) {
return {
success: false,
error: `Module directory already exists: ${modulePath}\nUse --force flag to overwrite or run in interactive mode to append.`,
};
}
// Create the main module directory
await (0, directory_operations_1.ensureDirectory)({ dirPath: modulePath });
// Create only the types subdirectory for phase 1
const typesDir = path.join(modulePath, 'types');
await (0, directory_operations_1.ensureDirectory)({ dirPath: typesDir });
return {
success: true,
moduleName: normalizedName,
modulePath,
createdDirectories: [modulePath, typesDir],
generatedFiles: [],
message: `ā
Phase 1: Created module directory and types folder for "${normalizedName}"`,
};
}
catch (error) {
return await handleGenerationError(error, moduleName, baseDir);
}
};
exports.generateModuleStructurePhase1 = generateModuleStructurePhase1;
/**
* Phase 2: Creates remaining subdirectories based on API type
* Used after user confirms the generated types
*/
const generateModuleStructurePhase2 = async ({ modulePath, apiType, trpcStyle = false, framework, }) => {
try {
// Get all subdirectories for this API type and style
const allSubdirectories = (0, path_utils_1.getModuleSubdirectories)(apiType, trpcStyle, framework);
// Filter out 'types' since it was already created in phase 1
const remainingSubdirectories = allSubdirectories.filter(dir => dir !== 'types');
// Create remaining subdirectories
const createdDirs = await (0, directory_operations_1.createDirectories)({
basePath: modulePath,
subdirectories: remainingSubdirectories,
});
return {
success: true,
createdDirectories: createdDirs,
};
}
catch (error) {
return {
success: false,
createdDirectories: [],
error: `Failed to create remaining directories: ${error.message}`,
};
}
};
exports.generateModuleStructurePhase2 = generateModuleStructurePhase2;
/**
* Formats a success message with the created structure
*/
const formatSuccessMessage = ({ moduleName, modulePath, apiType, }) => {
const subdirs = (0, path_utils_1.getModuleSubdirectories)(apiType, false, apiType?.framework);
const structure = subdirs.map(dir => ` āāā ${dir}/`).join('\n');
return `
ā
Successfully created API module structure for "${moduleName}"
š Created directory structure:
${modulePath}/
${structure}
š Your API module is ready for development!
`;
};
/**
* Handles generation errors with specific error types
*/
const handleGenerationError = async (error, moduleName, baseDir) => {
// Handle specific file system errors
if (error.code === 'EACCES') {
return {
success: false,
error: `Permission denied. Cannot create directories at: ${await (0, path_utils_1.getModulePath)({ moduleName, baseDir })}`,
};
}
if (error.code === 'ENOSPC') {
return {
success: false,
error: 'Not enough disk space to create the module structure',
};
}
if (error.code === 'ENOTDIR') {
return {
success: false,
error: 'Invalid path: A file exists where a directory is expected',
};
}
// Generic error handling
return {
success: false,
error: `Failed to create module structure: ${error.message}`,
};
};
//# sourceMappingURL=module-generator.service.js.map