wrekenfile-converter
Version:
Convert OpenAPI and Postman specs into Wrekenfiles, with chunking for vector database storage
377 lines • 15.1 kB
JavaScript
;
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.generateMiniWrekenfiles = generateMiniWrekenfiles;
exports.saveMiniWrekenfiles = saveMiniWrekenfiles;
const yaml = __importStar(require("js-yaml"));
const fs = __importStar(require("fs"));
const constants_1 = require("./utils/constants");
const yaml_utils_1 = require("./utils/yaml-utils");
function generateMiniWrekenfiles(wrekenfileContent) {
if (!wrekenfileContent || typeof wrekenfileContent !== 'string') {
throw new Error("Argument 'wrekenfileContent' is required and must be a string");
}
const data = yaml.load(wrekenfileContent);
if (!data.METHODS) {
throw new Error('No METHODS section found in Wrekenfile');
}
// v2.0.2-mini: One mini-wrekenfile per method (not grouped)
// CANONICAL_ID is already set in the main Wrekenfile METHODS
const miniWrekenfiles = [];
for (const [methodId, methodData] of Object.entries(data.METHODS)) {
const canonicalId = methodData.CANONICAL_ID;
miniWrekenfiles.push(createMiniWrekenfile(data, methodId, methodData, canonicalId));
}
return miniWrekenfiles;
}
// v2.0.2-mini: No grouping needed - one mini-wrekenfile per method
function createMiniWrekenfile(data, methodId, methodData, canonicalId) {
var _a, _b, _c, _d, _e, _f;
// Unified Mini-Wrekenfile v2.0.2: Execution-complete structure
const miniData = {
VERSION: '2.0.2',
METHOD: {
ID: methodId,
SUMMARY: methodData.SUMMARY || '',
},
};
if (canonicalId) {
miniData.METHOD.CANONICAL_ID = canonicalId;
}
if (methodData.DESC) {
miniData.METHOD.DESC = methodData.DESC;
}
// EXECUTION section
const execution = methodData.EXECUTION || {};
miniData.EXECUTION = {
KIND: execution.KIND || (methodData.HTTP ? 'http' : (methodData.SDK ? 'sdk' : 'http')),
MODE: execution.MODE || 'async',
EXECUTION_LEVEL: 'standalone',
};
// HTTP section (optional but include if present)
if (methodData.HTTP) {
miniData.HTTP = {
METHOD: methodData.HTTP.METHOD,
ENDPOINT: methodData.HTTP.ENDPOINT,
};
if (methodData.HTTP.CONTENT_TYPE) {
miniData.HTTP.CONTENT_TYPE = methodData.HTTP.CONTENT_TYPE;
}
if (methodData.HTTP.ACCEPT) {
miniData.HTTP.ACCEPT = methodData.HTTP.ACCEPT;
}
if (methodData.HTTP.HEADERS) {
miniData.HTTP.HEADERS = methodData.HTTP.HEADERS;
}
}
// SDK section (optional but include if present)
if (methodData.SDK) {
miniData.SDK = {
INTERFACE: methodData.SDK.INTERFACE ? {
NAME: methodData.SDK.INTERFACE.NAME,
} : undefined,
INVOCATION: methodData.SDK.INVOCATION ? {
TYPE: methodData.SDK.INVOCATION.TYPE,
RECEIVER: methodData.SDK.INVOCATION.RECEIVER,
} : undefined,
};
// Remove undefined fields
if (!miniData.SDK.INTERFACE)
delete miniData.SDK.INTERFACE;
if (!miniData.SDK.INVOCATION)
delete miniData.SDK.INVOCATION;
if (Object.keys(miniData.SDK).length === 0)
delete miniData.SDK;
}
else if (methodData.INTERFACE || methodData.INVOCATION) {
// Handle legacy format
miniData.SDK = {};
if ((_a = methodData.INTERFACE) === null || _a === void 0 ? void 0 : _a.NAME) {
miniData.SDK.INTERFACE = {
NAME: methodData.INTERFACE.NAME,
};
}
if (methodData.INVOCATION) {
miniData.SDK.INVOCATION = {
TYPE: methodData.INVOCATION.TYPE,
RECEIVER: methodData.INVOCATION.RECEIVER,
};
}
}
// INPUTS section - keep LOCATION and all details
if (methodData.INPUTS && methodData.INPUTS.length > 0) {
miniData.INPUTS = methodData.INPUTS.map((input) => {
const inputKey = Object.keys(input)[0];
const inputValue = input[inputKey];
if (typeof inputValue === 'string') {
// Simple form: - name: TYPE
// Need to determine LOCATION from context
const location = determineInputLocation(inputKey, methodData);
return {
name: inputKey,
TYPE: inputValue,
REQUIRED: true,
LOCATION: location,
};
}
else if (typeof inputValue === 'object') {
// Extended form: - name: { TYPE: ..., REQUIRED: ..., LOCATION: ... }
const cleanedInput = {
name: inputKey,
TYPE: inputValue.TYPE,
REQUIRED: inputValue.REQUIRED !== undefined ? inputValue.REQUIRED : true,
};
// Keep LOCATION if present, otherwise determine from context
if (inputValue.LOCATION) {
cleanedInput.LOCATION = inputValue.LOCATION;
}
else {
cleanedInput.LOCATION = determineInputLocation(inputKey, methodData);
}
// Keep DESC if present
if (inputValue.DESC) {
cleanedInput.DESC = inputValue.DESC;
}
return cleanedInput;
}
return null;
}).filter(Boolean);
}
// RETURNS section - single object with TYPE and DESC
if (methodData.RETURNS && methodData.RETURNS.length > 0) {
// Use the first return type
const firstReturn = methodData.RETURNS[0];
miniData.RETURNS = {
TYPE: firstReturn.RETURNTYPE || 'ANY',
};
if (firstReturn.DESC) {
miniData.RETURNS.DESC = firstReturn.DESC;
}
}
else if ((_c = (_b = methodData.ASYNC) === null || _b === void 0 ? void 0 : _b.RESULT) === null || _c === void 0 ? void 0 : _c.TYPE) {
miniData.RETURNS = {
TYPE: methodData.ASYNC.RESULT.TYPE,
};
}
// ERRORS section (optional)
if (methodData.ERRORS && methodData.ERRORS.length > 0) {
miniData.ERRORS = methodData.ERRORS.map((error) => ({
TYPE: error.TYPE || 'ANY',
WHEN: error.WHEN || '',
}));
}
// STRUCTS section - collect and include required structs
const requiredStructs = collectRequiredStructs(methodData, data.STRUCTS || {});
if (Object.keys(requiredStructs).length > 0) {
miniData.STRUCTS = requiredStructs;
}
// Generate YAML string
const content = (0, yaml_utils_1.generateYamlString)(miniData);
// Metadata
const metadata = {
methods: [methodId],
structs: Object.keys(requiredStructs),
filename: generateFilename(methodId, methodData),
};
if (canonicalId) {
metadata.canonicalId = canonicalId;
}
if ((_d = methodData.HTTP) === null || _d === void 0 ? void 0 : _d.ENDPOINT) {
metadata.endpoint = methodData.HTTP.ENDPOINT;
}
if ((_f = (_e = miniData.SDK) === null || _e === void 0 ? void 0 : _e.INTERFACE) === null || _f === void 0 ? void 0 : _f.NAME) {
metadata.interface = miniData.SDK.INTERFACE.NAME;
}
if (methodData.SOURCE) {
metadata.source = methodData.SOURCE;
}
return { content, metadata };
}
// Helper function to determine input location from context
function determineInputLocation(inputKey, methodData) {
var _a, _b, _c, _d;
// Check if it's a path parameter
if ((_a = methodData.HTTP) === null || _a === void 0 ? void 0 : _a.ENDPOINT) {
const endpoint = methodData.HTTP.ENDPOINT;
if (endpoint.includes(`{${inputKey}}`) || endpoint.includes(`{{${inputKey}}}`)) {
return 'path';
}
}
// Check if it's a header
if (((_b = methodData.HTTP) === null || _b === void 0 ? void 0 : _b.HEADERS) && methodData.HTTP.HEADERS[inputKey]) {
return 'header';
}
// Check if it's body
if (inputKey === 'body' || ((_d = (_c = methodData.HTTP) === null || _c === void 0 ? void 0 : _c.BODY) === null || _d === void 0 ? void 0 : _d.TYPE)) {
return 'body';
}
// Default to query for HTTP, sdk for SDK
if (methodData.HTTP) {
return 'query';
}
return 'sdk';
}
// Collect required structs for this method
function collectRequiredStructs(methodData, allStructs) {
var _a, _b, _c, _d;
const requiredStructs = {};
const processedStructs = new Set();
const structRefs = new Set();
// Extract struct references from INPUTS
if (methodData.INPUTS) {
for (const input of methodData.INPUTS) {
for (const value of Object.values(input)) {
const type = extractTypeFromInput(value);
if (type)
collectStructRefsFromType(type, structRefs);
}
}
}
// Extract struct references from RETURNS
if (methodData.RETURNS) {
for (const ret of methodData.RETURNS) {
if (ret.RETURNTYPE)
collectStructRefsFromType(ret.RETURNTYPE, structRefs);
}
}
// Extract struct references from ERRORS
if (methodData.ERRORS) {
for (const error of methodData.ERRORS) {
if (error.TYPE)
collectStructRefsFromType(error.TYPE, structRefs);
}
}
// Extract from HTTP.BODY.TYPE
if ((_b = (_a = methodData.HTTP) === null || _a === void 0 ? void 0 : _a.BODY) === null || _b === void 0 ? void 0 : _b.TYPE) {
collectStructRefsFromType(methodData.HTTP.BODY.TYPE, structRefs);
}
// Extract from ASYNC.RESULT.TYPE
if ((_d = (_c = methodData.ASYNC) === null || _c === void 0 ? void 0 : _c.RESULT) === null || _d === void 0 ? void 0 : _d.TYPE) {
collectStructRefsFromType(methodData.ASYNC.RESULT.TYPE, structRefs);
}
// Recursively collect structs
for (const structName of structRefs) {
collectStructRecursively(structName, allStructs, requiredStructs, processedStructs);
}
return requiredStructs;
}
function extractTypeFromInput(value) {
if (typeof value === 'string')
return value;
if (value && typeof value === 'object' && 'TYPE' in value)
return value.TYPE;
return null;
}
function collectStructRefsFromType(type, structRefs) {
const structNames = extractAllStructNames(type);
for (const structName of structNames) {
if (structName)
structRefs.add(structName);
}
}
function collectStructRecursively(structName, allStructs, requiredStructs, processedStructs) {
if (processedStructs.has(structName) || !allStructs[structName]) {
return;
}
processedStructs.add(structName);
requiredStructs[structName] = allStructs[structName];
// Check for nested structs in fields
const structData = allStructs[structName];
if (Array.isArray(structData)) {
// Old format: array of fields
for (const field of structData) {
if (field.type) {
const nestedStructNames = extractAllStructNames(field.type);
for (const nestedStructName of nestedStructNames) {
if (nestedStructName) {
collectStructRecursively(nestedStructName, allStructs, requiredStructs, processedStructs);
}
}
}
}
}
else if (structData && typeof structData === 'object' && structData.FIELDS) {
// New format: { DESC: ..., FIELDS: [...] }
for (const field of structData.FIELDS) {
if (field.TYPE) {
const nestedStructNames = extractAllStructNames(field.TYPE);
for (const nestedStructName of nestedStructNames) {
if (nestedStructName) {
collectStructRecursively(nestedStructName, allStructs, requiredStructs, processedStructs);
}
}
}
}
}
}
const STRUCT_REGEX = /^STRUCT\(([^)]+)\)/;
const ARRAY_STRUCT_REGEX = /^\[\]STRUCT\(([^)]+)\)/;
const MAP_STRUCT_REGEX = /map\[[^\]]+\]STRUCT\(([^)]+)\)/;
function extractAllStructNames(typeString) {
const matches = [];
const match1 = typeString.match(STRUCT_REGEX);
const match2 = typeString.match(ARRAY_STRUCT_REGEX);
const match3 = typeString.match(MAP_STRUCT_REGEX);
if (match1)
matches.push(match1[1]);
if (match2)
matches.push(match2[1]);
if (match3)
matches.push(match3[1]);
return matches;
}
function sanitizeFilename(name) {
return name
.replace(constants_1.FILENAME_LEADING_SLASHES, '')
.replace(constants_1.FILENAME_TRAILING_SLASHES, '')
.replace(constants_1.FILENAME_INVALID_CHARS, '-')
.replace(constants_1.FILENAME_MULTIPLE_HYPHENS, '-')
.replace(constants_1.FILENAME_LEADING_TRAILING_HYPHENS, '');
}
function generateFilename(methodId, _methodData) {
// v2.0.2-mini: One file per method, use method ID as filename
const cleanName = sanitizeFilename(methodId);
return `${constants_1.MINI_FILENAME_PREFIX}${cleanName}${constants_1.YAML_EXTENSION}`;
}
function saveMiniWrekenfiles(miniWrekenfiles, outputDir = constants_1.DEFAULT_MINI_OUTPUT_DIR) {
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
for (const miniFile of miniWrekenfiles) {
const filePath = `${outputDir}/${miniFile.metadata.filename}`;
fs.writeFileSync(filePath, miniFile.content);
}
}
//# sourceMappingURL=mini-wrekenfile-generator.js.map