From ace133f0b7973fb220f347acd540953e02516e5b Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 18 Mar 2026 14:46:40 +0800 Subject: [PATCH] fix: rewrite parser to correctly parse parent_subsystem and module hierarchy --- src/data/blueprintParser.ts | 287 ++++++++++++++++++++++-------------- 1 file changed, 179 insertions(+), 108 deletions(-) diff --git a/src/data/blueprintParser.ts b/src/data/blueprintParser.ts index 08f8feb..04110c8 100644 --- a/src/data/blueprintParser.ts +++ b/src/data/blueprintParser.ts @@ -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 | null = null; - let currentField = ''; - let currentList: string[] = []; + + let current: Partial = {}; + 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 | null = null; - let currentApi: { fn: string; params: { name: string; type: string }[]; returns?: { type: string } } | null = null; + + let current: Partial = {}; + 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 }; }