typescript-scaffolder
Version:
 
139 lines (138 loc) • 6.46 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deriveMethodName = deriveMethodName;
exports.generateSequenceRunner = generateSequenceRunner;
exports.generateSequenceFromFile = generateSequenceFromFile;
exports.generateSequencesFromPath = generateSequencesFromPath;
const sequence_tree_builder_1 = require("../../utils/sequence-tree-builder");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const structure_validators_1 = require("../../utils/structure-validators");
const logger_1 = require("../../utils/logger");
const file_system_1 = require("../../utils/file-system");
/**
* Used to create a normalised method name that reflects the REST API action
*
* @param node
*/
function deriveMethodName(node) {
const endpoint = node.step.endpoint || '';
const parts = endpoint.split('/')
.filter((p) => p && !p.startsWith(':'));
const objectName = parts[parts.length - 1] || 'unknown';
let method = 'get'; // default
if (node.type === 'fetchList')
method = 'getAll';
if (node.type === 'action') {
const actionStep = node.step;
method = actionStep.method.toLowerCase();
}
return `${method}_${objectName}`;
}
function interpolateTemplateObject(obj) {
if (typeof obj === 'string') {
const match = obj.match(/^{{(.+?)}}$/);
return match ? match[1] : JSON.stringify(obj);
}
else if (Array.isArray(obj)) {
return `[${obj.map(interpolateTemplateObject).join(', ')}]`;
}
else if (typeof obj === 'object' && obj !== null) {
const entries = Object.entries(obj).map(([key, value]) => {
return `${key}: ${interpolateTemplateObject(value)}`;
});
return `{ ${entries.join(', ')} }`;
}
else {
return JSON.stringify(obj);
}
}
function generateSequenceRunner(sequence, tree, outputPath, serviceName) {
const funcName = 'generateSequenceRunner';
logger_1.Logger.debug(funcName, 'Generating sequence file...');
const lines = [];
lines.push(`// Auto-generated runner for sequence: ${sequence.name}`);
lines.push(`// Service: ${serviceName}`);
lines.push(`import { apiRegistry } from "../registry";`);
lines.push(``);
lines.push(`export async function run${sequence.name}() {`);
function walk(node, depth = 1) {
const indent = ' '.repeat(depth);
switch (node.type) {
case 'fetchList': {
const fetchStep = node.step;
const varName = fetchStep.extract?.as || 'result';
const service = node.step.service || serviceName;
lines.push(`${indent}const response = await apiRegistry["${service}"].${deriveMethodName(node)}();`);
lines.push(`${indent}const ${varName} = response${fetchStep.extract?.field ? `.${fetchStep.extract.field}` : ''};`);
break;
}
case 'action': {
const actionStep = node.step;
const service = node.step.service || serviceName;
const methodName = deriveMethodName(node);
const paramMatches = (actionStep.endpoint.match(/:(\w+(?:\.\w+)?)/g) || []);
const paramArgs = paramMatches.map(p => p.slice(1));
const methodWithBody = ['put', 'post', 'patch'].includes(actionStep.method?.toLowerCase());
const argsList = [...paramArgs];
if (methodWithBody && actionStep.body) {
argsList.push(interpolateTemplateObject(actionStep.body));
}
if (actionStep.extract) {
lines.push(`${indent}const response = await apiRegistry["${service}"].${methodName}(${argsList.join(', ')});`);
lines.push(`${indent}const ${actionStep.extract.as} = response.${actionStep.extract.field};`);
}
else {
lines.push(`${indent}await apiRegistry["${service}"].${methodName}(${argsList.join(', ')});`);
}
break;
}
case 'loop': {
const loopStep = node.step;
const list = loopStep.over;
const item = loopStep.itemName;
lines.push(`${indent}for (const ${item} of ${list}) {`);
node.children.forEach(child => walk(child, depth + 1));
lines.push(`${indent}}`);
break;
}
}
}
tree.forEach(node => walk(node));
lines.push(`}`);
const outputFile = path_1.default.resolve(outputPath, `${sequence.name}.runner.ts`);
fs_1.default.writeFileSync(outputFile, lines.join('\n'), 'utf-8');
}
function generateSequenceFromFile(filePath, outputDir) {
const funcName = 'generateSequenceFromFile';
logger_1.Logger.debug(funcName, `Generating sequence from ${filePath} ...`);
const fileContent = fs_1.default.readFileSync(filePath, 'utf-8');
const parsed = JSON.parse(fileContent);
(0, structure_validators_1.assertSequences)(parsed);
for (const sequence of parsed.sequences) {
const tree = (0, sequence_tree_builder_1.buildTreeFromSequence)(sequence);
generateSequenceRunner(sequence, tree, outputDir, parsed.serviceName);
}
}
function generateSequencesFromPath(configDir, outputDir, subDir = 'sequences') {
const funcName = 'generateSequencesFromPath';
logger_1.Logger.debug(funcName, `Generating sequences from ${configDir} to ${outputDir}`);
const files = fs_1.default.readdirSync(configDir).filter(f => f.endsWith('.json'));
for (const file of files) {
const filePath = path_1.default.join(configDir, file);
const content = fs_1.default.readFileSync(filePath, 'utf-8');
const parsed = JSON.parse(content);
const serviceName = parsed.serviceName;
if (!serviceName) {
logger_1.Logger.warn(funcName, `Skipping file ${file} — missing 'serviceName' field`);
continue;
}
const serviceOutputDir = path_1.default.join(outputDir, subDir);
(0, file_system_1.ensureDir)(serviceOutputDir);
generateSequenceFromFile(filePath, serviceOutputDir);
}
logger_1.Logger.info(funcName, 'Sequence file generation completed.');
}