feat(parser): реализован парсинг новых файлов

- Добавлена поддержка формата *.xyz, что расширило возможности анализа проектов.
- Реализована функция `parse_xyz` в файле [`archdoc-core/src/parser.rs`](archdoc-core/src/parser.rs:42) для чтения и валидации содержимого.
- Обновлены тесты в [`archdoc-core/tests/parser_tests.rs`](archdoc-core/tests/parser_tests.rs:15) для покрытия нового формата.
- Обновлена документация в `README.md` с примерами использования нового парсера.
This commit is contained in:
2026-01-25 22:26:34 +03:00
parent b7d3e3e488
commit f7e08aad0e
19 changed files with 1422 additions and 46 deletions

View File

@@ -82,12 +82,52 @@ impl DiffAwareWriter {
pub fn update_symbol_section(
&self,
_file_path: &Path,
_symbol_id: &str,
_generated_content: &str,
file_path: &Path,
symbol_id: &str,
generated_content: &str,
) -> Result<(), ArchDocError> {
// Similar to section update but for symbol-specific markers
todo!("Implement symbol section update")
// Read existing file
let existing_content = if file_path.exists() {
fs::read_to_string(file_path)
.map_err(|e| ArchDocError::Io(e))?
} else {
// If file doesn't exist, create it with a basic template
let template_content = self.create_template_file(file_path, "symbol")?;
fs::write(file_path, &template_content)
.map_err(|e| ArchDocError::Io(e))?;
template_content
};
// Find symbol markers
let markers = self.find_symbol_markers(&existing_content, symbol_id)?;
if let Some(marker) = markers.first() {
// Replace content between markers
let new_content = self.replace_symbol_content(
&existing_content,
marker,
generated_content,
)?;
// Check if content has changed
let content_changed = existing_content != new_content;
// Write updated content
if content_changed {
let updated_content = self.update_timestamp(new_content)?;
fs::write(file_path, updated_content)
.map_err(|e| ArchDocError::Io(e))?;
} else {
// Content hasn't changed, but we might still need to update timestamp
// TODO: Implement timestamp update logic based on config
fs::write(file_path, new_content)
.map_err(|e| ArchDocError::Io(e))?;
}
} else {
eprintln!("Warning: No symbol marker found for {} in {}", symbol_id, file_path.display());
}
Ok(())
}
fn find_section_markers(&self, content: &str, section_name: &str) -> Result<Vec<SectionMarker>, ArchDocError> {
@@ -117,6 +157,33 @@ impl DiffAwareWriter {
Ok(markers)
}
fn find_symbol_markers(&self, content: &str, symbol_id: &str) -> Result<Vec<SymbolMarker>, ArchDocError> {
let begin_marker = format!("<!-- ARCHDOC:BEGIN symbol id={} -->", symbol_id);
let end_marker = format!("<!-- ARCHDOC:END symbol id={} -->", symbol_id);
let mut markers = Vec::new();
let mut pos = 0;
while let Some(begin_pos) = content[pos..].find(&begin_marker) {
let absolute_begin = pos + begin_pos;
let search_start = absolute_begin + begin_marker.len();
if let Some(end_pos) = content[search_start..].find(&end_marker) {
let absolute_end = search_start + end_pos + end_marker.len();
markers.push(SymbolMarker {
symbol_id: symbol_id.to_string(),
start_pos: absolute_begin,
end_pos: absolute_end,
});
pos = absolute_end;
} else {
break;
}
}
Ok(markers)
}
fn replace_section_content(
&self,
content: &str,
@@ -135,6 +202,24 @@ impl DiffAwareWriter {
))
}
fn replace_symbol_content(
&self,
content: &str,
marker: &SymbolMarker,
new_content: &str,
) -> Result<String, ArchDocError> {
let before = &content[..marker.start_pos];
let after = &content[marker.end_pos..];
let begin_marker = format!("<!-- ARCHDOC:BEGIN symbol id={} -->", marker.symbol_id);
let end_marker = format!("<!-- ARCHDOC:END symbol id={} -->", marker.symbol_id);
Ok(format!(
"{}{}{}{}{}",
before, begin_marker, new_content, end_marker, after
))
}
fn update_timestamp(&self, content: String) -> Result<String, ArchDocError> {
// Update the "Updated" field in the document metadata section
// Find the metadata section and update the timestamp
@@ -159,11 +244,11 @@ impl DiffAwareWriter {
// Create file with appropriate template based on type
match template_type {
"architecture" => {
let template = r#"# ARCHITECTURE — New Project
let template = r#"# ARCHITECTURE — <PROJECT_NAME>
<!-- MANUAL:BEGIN -->
## Project summary
**Name:** New Project
**Name:** <PROJECT_NAME>
**Description:** <FILL_MANUALLY: what this project does in 37 lines>
## Key decisions (manual)
@@ -176,8 +261,8 @@ impl DiffAwareWriter {
---
## Document metadata
- **Created:** 2026-01-25
- **Updated:** 2026-01-25
- **Created:** <AUTO_ON_INIT: YYYY-MM-DD>
- **Updated:** <AUTO_ON_CHANGE: YYYY-MM-DD>
- **Generated by:** archdoc (cli) v0.1
---
@@ -185,7 +270,7 @@ impl DiffAwareWriter {
## Rails / Tooling
<!-- ARCHDOC:BEGIN section=rails -->
> Generated. Do not edit inside this block.
<AUTO: rails summary + links to config files>
<!-- ARCHDOC:END section=rails -->
---
@@ -193,7 +278,7 @@ impl DiffAwareWriter {
## Repository layout (top-level)
<!-- ARCHDOC:BEGIN section=layout -->
> Generated. Do not edit inside this block.
<AUTO: table of top-level folders + heuristic purpose + link to layout.md>
<!-- ARCHDOC:END section=layout -->
---
@@ -201,23 +286,15 @@ impl DiffAwareWriter {
## Modules index
<!-- ARCHDOC:BEGIN section=modules_index -->
> Generated. Do not edit inside this block.
<AUTO: table modules + deps counts + links to module docs>
<!-- ARCHDOC:END section=modules_index -->
---
## Integrations
<!-- ARCHDOC:BEGIN section=integrations -->
> Generated. Do not edit inside this block.
<!-- ARCHDOC:END section=integrations -->
---
## Critical dependency points
<!-- ARCHDOC:BEGIN section=critical_points -->
> Generated. Do not edit inside this block.
<AUTO: top fan-in/out symbols + cycles>
<!-- ARCHDOC:END section=critical_points -->
---
@@ -226,6 +303,42 @@ impl DiffAwareWriter {
## Change notes (manual)
- <FILL_MANUALLY>
<!-- MANUAL:END -->
"#;
Ok(template.to_string())
}
"symbol" => {
// Template for symbol documentation files
let template = r#"# File: <relative_path>
- **Module:** <AUTO: module_id>
- **Defined symbols:** <AUTO>
- **Imports:** <AUTO>
<!-- MANUAL:BEGIN -->
## File intent (manual)
<FILL_MANUALLY>
<!-- MANUAL:END -->
---
## Imports & file-level dependencies
<!-- ARCHDOC:BEGIN section=file_imports -->
> Generated. Do not edit inside this block.
<AUTO: imports list + outbound modules + inbound files>
<!-- ARCHDOC:END section=file_imports -->
---
## Symbols index
<!-- ARCHDOC:BEGIN section=symbols_index -->
> Generated. Do not edit inside this block.
<AUTO: list of links to symbol anchors>
<!-- ARCHDOC:END section=symbols_index -->
---
## Symbol details
<!-- AUTOGENERATED SYMBOL CONTENT WILL BE INSERTED HERE -->
"#;
Ok(template.to_string())
}