feat: spec graph
This commit is contained in:
80
server.js
Normal file
80
server.js
Normal file
@@ -0,0 +1,80 @@
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
app.use(express.json({ limit: '2mb' }));
|
||||
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({ status: 'ok' });
|
||||
});
|
||||
|
||||
function buildGraphFromPaths(pathsObject) {
|
||||
const httpMethods = new Set(['get','put','post','delete','options','head','patch','trace']);
|
||||
const nodeIdSet = new Set();
|
||||
const linkKeySet = new Set();
|
||||
const nodes = [];
|
||||
const links = [];
|
||||
const endpoints = [];
|
||||
|
||||
for (const pathKey of Object.keys(pathsObject || {})) {
|
||||
const pathItem = pathsObject[pathKey] || {};
|
||||
// Collect endpoints
|
||||
for (const method of Object.keys(pathItem)) {
|
||||
const lower = method.toLowerCase();
|
||||
if (httpMethods.has(lower)) {
|
||||
endpoints.push({ method: lower.toUpperCase(), path: pathKey });
|
||||
}
|
||||
}
|
||||
// Build nodes/links from URL segments
|
||||
const segments = pathKey.split('/').filter(Boolean);
|
||||
if (segments.length === 0) continue;
|
||||
|
||||
// Ensure nodes
|
||||
for (const seg of segments) {
|
||||
if (!nodeIdSet.has(seg)) {
|
||||
nodeIdSet.add(seg);
|
||||
nodes.push({ id: seg });
|
||||
}
|
||||
}
|
||||
|
||||
// Create sequential links along the path
|
||||
for (let i = 0; i < segments.length - 1; i++) {
|
||||
const source = segments[i];
|
||||
const target = segments[i + 1];
|
||||
const key = `${source}|${target}`;
|
||||
if (!linkKeySet.has(key)) {
|
||||
linkKeySet.add(key);
|
||||
links.push({ source, target });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { nodes, links, endpoints };
|
||||
}
|
||||
|
||||
app.post('/api/parse', (req, res) => {
|
||||
try {
|
||||
const { yaml: yamlText } = req.body || {};
|
||||
if (typeof yamlText !== 'string' || yamlText.trim() === '') {
|
||||
return res.status(400).json({ error: 'Missing yaml string in body' });
|
||||
}
|
||||
const spec = yaml.load(yamlText);
|
||||
if (!spec || typeof spec !== 'object') {
|
||||
return res.status(400).json({ error: 'Invalid YAML content' });
|
||||
}
|
||||
|
||||
const pathsObject = spec.paths || {};
|
||||
const graph = buildGraphFromPaths(pathsObject);
|
||||
res.json({ graph, info: { title: spec.info && spec.info.title, version: spec.info && spec.info.version } });
|
||||
} catch (err) {
|
||||
res.status(400).json({ error: err.message || 'Failed to parse YAML' });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server listening on http://localhost:${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user