fix: rewrite parser to correctly parse parent_subsystem and module hierarchy
This commit is contained in:
@@ -46,148 +46,219 @@ function extractYamlBlock(markdown: string, sectionName: string): string {
|
||||
return match ? match[1].trim() : '';
|
||||
}
|
||||
|
||||
function parseSubsystemList(yaml: string): Subsystem[] {
|
||||
function parseSubsystems(yaml: string): Subsystem[] {
|
||||
const subsystems: Subsystem[] = [];
|
||||
const lines = yaml.split('\n');
|
||||
let currentSubsystem: Partial<Subsystem> | null = null;
|
||||
let currentField = '';
|
||||
let currentList: string[] = [];
|
||||
|
||||
let current: Partial<Subsystem> = {};
|
||||
let currentField: string | null = null;
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.includes('- name:')) {
|
||||
if (currentSubsystem && currentSubsystem.name) {
|
||||
const trimmed = line.trim();
|
||||
|
||||
if (trimmed.startsWith('subsystems:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('- name:')) {
|
||||
if (current.name) {
|
||||
subsystems.push({
|
||||
id: currentSubsystem.name,
|
||||
name: currentSubsystem.name,
|
||||
responsibilities: currentSubsystem.responsibilities || [],
|
||||
provides: currentSubsystem.provides || [],
|
||||
depends_on: currentSubsystem.depends_on || [],
|
||||
boundary: currentSubsystem.boundary
|
||||
id: current.name,
|
||||
name: current.name,
|
||||
responsibilities: current.responsibilities || [],
|
||||
provides: current.provides || [],
|
||||
depends_on: current.depends_on || [],
|
||||
boundary: current.boundary
|
||||
});
|
||||
}
|
||||
currentSubsystem = { name: line.split('- name:')[1].trim() };
|
||||
currentField = '';
|
||||
currentList = [];
|
||||
} else if (currentSubsystem && line.includes('responsibilities:')) {
|
||||
current = {
|
||||
name: trimmed.replace('- name:', '').trim(),
|
||||
responsibilities: [],
|
||||
provides: [],
|
||||
depends_on: []
|
||||
};
|
||||
currentField = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!current.name) continue;
|
||||
|
||||
if (trimmed.startsWith('responsibilities:')) {
|
||||
currentField = 'responsibilities';
|
||||
currentList = [];
|
||||
} else if (currentSubsystem && line.includes('provides:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('provides:')) {
|
||||
currentField = 'provides';
|
||||
currentList = [];
|
||||
} else if (currentSubsystem && line.includes('depends_on:')) {
|
||||
currentField = 'depends_on';
|
||||
currentList = [];
|
||||
} else if (currentSubsystem && line.includes('boundary:')) {
|
||||
currentField = 'boundary';
|
||||
currentSubsystem.boundary = { inputs: [], outputs: [] };
|
||||
} else if (currentSubsystem && currentField === 'responsibilities' && line.includes('-')) {
|
||||
const val = line.replace('-', '').trim().replace(/"/g, '');
|
||||
if (val) currentList.push(val);
|
||||
currentSubsystem.responsibilities = [...currentList];
|
||||
} else if (currentSubsystem && currentField === 'provides' && line.includes('[')) {
|
||||
const match = line.match(/\[(.*?)\]/);
|
||||
const match = trimmed.match(/\[(.*?)\]/);
|
||||
if (match) {
|
||||
currentSubsystem.provides = match[1].split(',').map(s => s.trim());
|
||||
}
|
||||
} else if (currentSubsystem && currentField === 'depends_on' && line.includes('[')) {
|
||||
const match = line.match(/\[(.*?)\]/);
|
||||
if (match && match[1].trim()) {
|
||||
currentSubsystem.depends_on = match[1].split(',').map(s => s.trim());
|
||||
current.provides = match[1].split(',').map(s => s.trim());
|
||||
} else {
|
||||
currentSubsystem.depends_on = [];
|
||||
current.provides = [];
|
||||
}
|
||||
} else if (currentSubsystem && currentField === 'boundary' && line.includes('inputs:')) {
|
||||
const match = line.match(/\[(.*?)\]/);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('depends_on:')) {
|
||||
currentField = 'depends_on';
|
||||
const match = trimmed.match(/\[(.*?)\]/);
|
||||
if (match && match[1].trim()) {
|
||||
current.depends_on = match[1].split(',').map(s => s.trim());
|
||||
} else {
|
||||
current.depends_on = [];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('boundary:')) {
|
||||
currentField = 'boundary';
|
||||
current.boundary = { inputs: [], outputs: [] };
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentField === 'responsibilities' && trimmed.startsWith('-')) {
|
||||
const val = trimmed.replace('-', '').trim().replace(/"/g, '');
|
||||
if (val) {
|
||||
current.responsibilities = current.responsibilities || [];
|
||||
current.responsibilities.push(val);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentField === 'boundary' && trimmed.startsWith('inputs:')) {
|
||||
const match = trimmed.match(/\[(.*?)\]/);
|
||||
if (match) {
|
||||
currentSubsystem.boundary!.inputs = match[1].split(',').map(s => s.trim());
|
||||
current.boundary!.inputs = match[1].split(',').map(s => s.trim());
|
||||
}
|
||||
} else if (currentSubsystem && currentField === 'boundary' && line.includes('outputs:')) {
|
||||
const match = line.match(/\[(.*?)\]/);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentField === 'boundary' && trimmed.startsWith('outputs:')) {
|
||||
const match = trimmed.match(/\[(.*?)\]/);
|
||||
if (match) {
|
||||
currentSubsystem.boundary!.outputs = match[1].split(',').map(s => s.trim());
|
||||
current.boundary!.outputs = match[1].split(',').map(s => s.trim());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSubsystem && currentSubsystem.name) {
|
||||
if (current.name) {
|
||||
subsystems.push({
|
||||
id: currentSubsystem.name,
|
||||
name: currentSubsystem.name,
|
||||
responsibilities: currentSubsystem.responsibilities || [],
|
||||
provides: currentSubsystem.provides || [],
|
||||
depends_on: currentSubsystem.depends_on || [],
|
||||
boundary: currentSubsystem.boundary
|
||||
id: current.name,
|
||||
name: current.name,
|
||||
responsibilities: current.responsibilities || [],
|
||||
provides: current.provides || [],
|
||||
depends_on: current.depends_on || [],
|
||||
boundary: current.boundary
|
||||
});
|
||||
}
|
||||
|
||||
return subsystems;
|
||||
}
|
||||
|
||||
function parseModuleList(yaml: string): Module[] {
|
||||
function parseModules(yaml: string): Module[] {
|
||||
const modules: Module[] = [];
|
||||
const lines = yaml.split('\n');
|
||||
let currentModule: Partial<Module> | null = null;
|
||||
let currentApi: { fn: string; params: { name: string; type: string }[]; returns?: { type: string } } | null = null;
|
||||
|
||||
let current: Partial<Module> = {};
|
||||
let currentApi: Module['public_api'][0] | null = null;
|
||||
let inPublicApi = false;
|
||||
let currentField = '';
|
||||
let inParams = false;
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.includes('- name:') && line.includes('parent_subsystem:')) {
|
||||
if (currentModule && currentModule.name && currentModule.parent_subsystem) {
|
||||
const trimmed = line.trim();
|
||||
|
||||
if (trimmed.startsWith('modules:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('- name:')) {
|
||||
if (current.name && current.parent_subsystem) {
|
||||
modules.push({
|
||||
id: currentModule.name,
|
||||
name: currentModule.name,
|
||||
parent_subsystem: currentModule.parent_subsystem,
|
||||
responsibility: currentModule.responsibility || '',
|
||||
public_api: currentModule.public_api || []
|
||||
id: current.name,
|
||||
name: current.name,
|
||||
parent_subsystem: current.parent_subsystem,
|
||||
responsibility: current.responsibility || '',
|
||||
public_api: current.public_api || []
|
||||
});
|
||||
}
|
||||
const nameMatch = line.match(/- name:\s*(\S+)/);
|
||||
const parentMatch = line.match(/parent_subsystem:\s*(\S+)/);
|
||||
currentModule = {
|
||||
name: nameMatch ? nameMatch[1] : '',
|
||||
parent_subsystem: parentMatch ? parentMatch[1] : '',
|
||||
current = {
|
||||
name: trimmed.replace('- name:', '').trim(),
|
||||
parent_subsystem: '',
|
||||
responsibility: '',
|
||||
public_api: []
|
||||
};
|
||||
inPublicApi = false;
|
||||
} else if (currentModule && line.includes('responsibility:')) {
|
||||
const match = line.match(/responsibility:\s*"(.+)"/);
|
||||
inParams = false;
|
||||
currentApi = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!current.name) continue;
|
||||
|
||||
if (trimmed.startsWith('parent_subsystem:')) {
|
||||
current.parent_subsystem = trimmed.replace('parent_subsystem:', '').trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('responsibility:')) {
|
||||
const match = trimmed.match(/responsibility:\s*"(.+)"/);
|
||||
if (match) {
|
||||
currentModule.responsibility = match[1];
|
||||
current.responsibility = match[1];
|
||||
}
|
||||
} else if (currentModule && line.includes('public_api:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('public_api:')) {
|
||||
inPublicApi = true;
|
||||
} else if (currentModule && inPublicApi && line.includes('- fn:')) {
|
||||
const fnMatch = line.match(/- fn:\s*(\S+)/);
|
||||
if (fnMatch) {
|
||||
currentApi = { fn: fnMatch[1], params: [] };
|
||||
currentModule.public_api = currentModule.public_api || [];
|
||||
currentModule.public_api.push(currentApi);
|
||||
}
|
||||
} else if (currentModule && currentApi && line.includes('params:')) {
|
||||
currentField = 'params';
|
||||
} else if (currentModule && currentApi && line.includes('returns:')) {
|
||||
currentField = 'returns';
|
||||
const returnsMatch = line.match(/returns:\s*type:\s*(\S+)/);
|
||||
if (returnsMatch) {
|
||||
currentApi.returns = { type: returnsMatch[1] };
|
||||
}
|
||||
} else if (currentModule && currentApi && currentField === 'params' && line.includes('name:')) {
|
||||
const nameMatch = line.match(/name:\s*(\S+)/);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inPublicApi && trimmed.startsWith('- fn:')) {
|
||||
currentApi = {
|
||||
fn: trimmed.replace('- fn:', '').trim(),
|
||||
params: []
|
||||
};
|
||||
current.public_api = current.public_api || [];
|
||||
current.public_api.push(currentApi);
|
||||
inParams = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentApi && trimmed.startsWith('params:')) {
|
||||
inParams = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentApi && inParams && trimmed.startsWith('- name:')) {
|
||||
const nameMatch = trimmed.match(/- name:\s*(\S+)/);
|
||||
const typeMatch = line.match(/type:\s*(\S+)/);
|
||||
if (nameMatch && typeMatch) {
|
||||
currentApi.params.push({ name: nameMatch[1], type: typeMatch[1] });
|
||||
currentApi.params.push({
|
||||
name: nameMatch[1],
|
||||
type: typeMatch[1]
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentApi && trimmed.startsWith('returns:')) {
|
||||
const match = trimmed.match(/returns:\s*type:\s*(\S+)/);
|
||||
if (match) {
|
||||
currentApi.returns = { type: match[1] };
|
||||
}
|
||||
inParams = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentModule && currentModule.name) {
|
||||
if (current.name && current.parent_subsystem) {
|
||||
modules.push({
|
||||
id: currentModule.name,
|
||||
name: currentModule.name,
|
||||
parent_subsystem: currentModule.parent_subsystem || '',
|
||||
responsibility: currentModule.responsibility || '',
|
||||
public_api: currentModule.public_api || []
|
||||
id: current.name,
|
||||
name: current.name,
|
||||
parent_subsystem: current.parent_subsystem,
|
||||
responsibility: current.responsibility || '',
|
||||
public_api: current.public_api || []
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,22 +279,22 @@ export function parseBlueprintFromMd(markdown: string): BlueprintData {
|
||||
|
||||
const metaLines = metaYaml.split('\n');
|
||||
for (const line of metaLines) {
|
||||
if (line.includes('name:')) {
|
||||
meta.name = line.split('name:')[1].trim().replace(/"/g, '');
|
||||
} else if (line.includes('version:')) {
|
||||
const ver = line.split('version:')[1].trim();
|
||||
meta.version = ver;
|
||||
} else if (line.includes('type:')) {
|
||||
meta.type = line.split('type:')[1].trim().replace(/"/g, '');
|
||||
} else if (line.includes('description:')) {
|
||||
meta.description = line.split('description:')[1].trim().replace(/"/g, '');
|
||||
} else if (line.includes('target_runtime:')) {
|
||||
meta.target_runtime = line.split('target_runtime:')[1].trim().replace(/"/g, '');
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith('name:')) {
|
||||
meta.name = trimmed.replace('name:', '').trim().replace(/"/g, '');
|
||||
} else if (trimmed.startsWith('version:')) {
|
||||
meta.version = trimmed.replace('version:', '').trim();
|
||||
} else if (trimmed.startsWith('type:')) {
|
||||
meta.type = trimmed.replace('type:', '').trim().replace(/"/g, '');
|
||||
} else if (trimmed.startsWith('description:')) {
|
||||
meta.description = trimmed.replace('description:', '').trim().replace(/"/g, '');
|
||||
} else if (trimmed.startsWith('target_runtime:')) {
|
||||
meta.target_runtime = trimmed.replace('target_runtime:', '').trim().replace(/"/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
const subsystems = parseSubsystemList(structureYaml);
|
||||
const modules = parseModuleList(structureYaml);
|
||||
const subsystems = parseSubsystems(structureYaml);
|
||||
const modules = parseModules(structureYaml);
|
||||
|
||||
return { meta, subsystems, modules };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user