fix: rewrite parser to correctly parse parent_subsystem and module hierarchy

This commit is contained in:
2026-03-18 14:46:40 +08:00
parent 6c7ba142ba
commit ace133f0b7

View File

@@ -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 };
}