mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-17 22:13:08 +00:00
* feat: add three viewing modes for app specification Introduces View, Edit, and Source modes for the spec page: - View: Clean read-only display with cards, badges, and accordions - Edit: Structured form-based editor for all spec fields - Source: Raw XML editor for advanced users Also adds @automaker/spec-parser shared package for XML parsing between server and client. * fix: address PR review feedback - Replace array index keys with stable UUIDs in array-field-editor, features-section, and roadmap-section components - Replace regex-based XML parsing with fast-xml-parser for robustness - Simplify renderContent logic in spec-view by removing dead code paths * fix: convert git+ssh URLs to https in package-lock.json * fix: address PR review feedback for spec visualiser - Remove unused RefreshCw import from spec-view.tsx - Add explicit parsedSpec check in renderContent for robustness - Hide save button in view mode since it's read-only - Remove GripVertical drag handles since drag-and-drop is not implemented - Rename Map imports to MapIcon to avoid shadowing global Map - Escape tagName in xml-utils.ts RegExp functions for safety - Add aria-label attributes for accessibility on mode tabs * fix: address additional PR review feedback - Fix Textarea controlled/uncontrolled warning with default value - Preserve IDs in useEffect sync to avoid unnecessary remounts - Consolidate lucide-react imports - Add JSDoc note about tag attributes limitation in xml-utils.ts - Remove redundant disabled prop from SpecModeTabs
89 lines
2.7 KiB
TypeScript
89 lines
2.7 KiB
TypeScript
/**
|
|
* SpecOutput to XML converter.
|
|
* Converts a structured SpecOutput object back to XML format.
|
|
*/
|
|
|
|
import type { SpecOutput } from '@automaker/types';
|
|
import { escapeXml } from './xml-utils.js';
|
|
|
|
/**
|
|
* Convert structured spec output to XML format.
|
|
*
|
|
* @param spec - The SpecOutput object to convert
|
|
* @returns XML string formatted for app_spec.txt
|
|
*/
|
|
export function specToXml(spec: SpecOutput): string {
|
|
const indent = ' ';
|
|
|
|
let xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<project_specification>
|
|
${indent}<project_name>${escapeXml(spec.project_name)}</project_name>
|
|
|
|
${indent}<overview>
|
|
${indent}${indent}${escapeXml(spec.overview)}
|
|
${indent}</overview>
|
|
|
|
${indent}<technology_stack>
|
|
${spec.technology_stack.map((t) => `${indent}${indent}<technology>${escapeXml(t)}</technology>`).join('\n')}
|
|
${indent}</technology_stack>
|
|
|
|
${indent}<core_capabilities>
|
|
${spec.core_capabilities.map((c) => `${indent}${indent}<capability>${escapeXml(c)}</capability>`).join('\n')}
|
|
${indent}</core_capabilities>
|
|
|
|
${indent}<implemented_features>
|
|
${spec.implemented_features
|
|
.map(
|
|
(f) => `${indent}${indent}<feature>
|
|
${indent}${indent}${indent}<name>${escapeXml(f.name)}</name>
|
|
${indent}${indent}${indent}<description>${escapeXml(f.description)}</description>${
|
|
f.file_locations && f.file_locations.length > 0
|
|
? `\n${indent}${indent}${indent}<file_locations>
|
|
${f.file_locations.map((loc) => `${indent}${indent}${indent}${indent}<location>${escapeXml(loc)}</location>`).join('\n')}
|
|
${indent}${indent}${indent}</file_locations>`
|
|
: ''
|
|
}
|
|
${indent}${indent}</feature>`
|
|
)
|
|
.join('\n')}
|
|
${indent}</implemented_features>`;
|
|
|
|
// Optional sections
|
|
if (spec.additional_requirements && spec.additional_requirements.length > 0) {
|
|
xml += `
|
|
|
|
${indent}<additional_requirements>
|
|
${spec.additional_requirements.map((r) => `${indent}${indent}<requirement>${escapeXml(r)}</requirement>`).join('\n')}
|
|
${indent}</additional_requirements>`;
|
|
}
|
|
|
|
if (spec.development_guidelines && spec.development_guidelines.length > 0) {
|
|
xml += `
|
|
|
|
${indent}<development_guidelines>
|
|
${spec.development_guidelines.map((g) => `${indent}${indent}<guideline>${escapeXml(g)}</guideline>`).join('\n')}
|
|
${indent}</development_guidelines>`;
|
|
}
|
|
|
|
if (spec.implementation_roadmap && spec.implementation_roadmap.length > 0) {
|
|
xml += `
|
|
|
|
${indent}<implementation_roadmap>
|
|
${spec.implementation_roadmap
|
|
.map(
|
|
(r) => `${indent}${indent}<phase>
|
|
${indent}${indent}${indent}<name>${escapeXml(r.phase)}</name>
|
|
${indent}${indent}${indent}<status>${escapeXml(r.status)}</status>
|
|
${indent}${indent}${indent}<description>${escapeXml(r.description)}</description>
|
|
${indent}${indent}</phase>`
|
|
)
|
|
.join('\n')}
|
|
${indent}</implementation_roadmap>`;
|
|
}
|
|
|
|
xml += `
|
|
</project_specification>`;
|
|
|
|
return xml;
|
|
}
|