Skip to content

feat(c4): add @c4 code level (struct/enum/trait/fn) + code diagram - #9

Open
nightscape wants to merge 2 commits into
GitSmart86:mainfrom
nightscape:feat/c4-code-level
Open

nightscape wants to merge 2 commits into
GitSmart86:mainfrom
nightscape:feat/c4-code-level

Conversation

@nightscape

Copy link
Copy Markdown

What

Adds the bottom of the C4 model. Item-level @c4 code doc markers on struct / enum / trait / fn become curated code-level nodes under their component. The rust adapter previously parsed only module //! docs.

  • archidoc-types: CodeElement on ModuleDoc + ir::CodeElement on DirNode (both serde-default, so existing IR JSON stays valid).
  • archidoc-rust/parser: extract_code_elements() uses syn to find items whose doc contains @c4 code; captures kind, description, and @c4 uses relationships. Unmarked items are ignored — the diagram is a curated set of load-bearing types, not a dump of every symbol.
  • archidoc-rust/walker: aggregates a module's code elements from its directory's source files onto the component's ModuleDoc.
  • archidoc-engine: ir_builder propagates code_elements; plantuml::generate_code() renders c4-code.puml (one Component(...) per element, kind as the tech tag, intra-component @c4 uses resolved to qualified ids). Emitted only when a code element exists.

Example

/// @c4 code
/// The seam every storage backend implements.
/// @c4 uses StorageEntity "yields rows as" "Rust"
pub trait FileFormatAdapter {}

/// @c4 code
pub struct StorageEntity {}

pub struct InternalHelper {} // no marker → excluded

c4-code.puml with FileFormatAdapter + StorageEntity as components and an arrow between them; InternalHelper is omitted.

Notes

@c4 code items are collected per component directory (the walker aggregates a module's source files). Items in deeper un-annotated subdirectories are not yet picked up — a reasonable follow-up. Test added covering curation, typing, and relationships.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds support for curated code-level (@c4 code) elements to the architecture IR and emits a dedicated PlantUML “code diagram” for them.

Changes:

  • Introduces CodeElement in module docs and IR; overlays extracted elements into the directory tree and merge logic.
  • Extends the Rust adapter to parse @c4 code elements (struct/enum/trait/fn) from item docs, including @c4 uses relationships.
  • Adds generate_code to emit c4-code.puml and wires it into the CLI render flow.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
core/archidoc-types/src/module_doc.rs Adds module-doc CodeElement and exposes it on ModuleDoc.
core/archidoc-types/src/lib.rs Re-exports CodeElement at the crate root.
core/archidoc-types/src/ir.rs Adds IR-level code_elements on DirNode and defines an IR CodeElement.
core/archidoc-engine/src/tree.rs Initializes code_elements when building the dir tree.
core/archidoc-engine/src/plantuml.rs Implements generate_code to emit c4-code.puml.
core/archidoc-engine/src/merge.rs Merges code_elements alongside other dir fields.
core/archidoc-engine/src/ir_builder.rs Overlays ModuleDoc.code_elements into IR DirNode.code_elements.
core/archidoc-cli/src/main.rs Calls generate_code during PlantUML rendering.
adapters/archidoc-rust/src/walker.rs Extracts code elements across sources (special-casing entry modules).
adapters/archidoc-rust/src/parser.rs Parses @c4 code elements using syn and adds unit test coverage.
adapters/archidoc-rust/src/cargo_modules.rs Updates test fixtures to include code_elements.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/archidoc-types/src/lib.rs Outdated
pub use ir::{ArchitectureIR, C4Level, DirNode, FileNode};
pub use scaffold_ir::{ScaffoldIR, ScaffoldNode, ScaffoldPostHook, ScaffoldTemplate, ScaffoldVariable};
pub use module_doc::{FileEntry, ModuleDoc, Relationship};
pub use module_doc::{CodeElement, FileEntry, ModuleDoc, Relationship};
Comment on lines +145 to +156
// Map a code element's bare name to its qualified puml id so that
// intra-component `@c4 uses StorageEntity` arrows land on the defined node
// instead of auto-creating a bare one.
let mut by_name: BTreeMap<&str, String> = BTreeMap::new();
for owner in &owners {
for el in &owner.code_elements {
by_name.insert(
el.name.as_str(),
to_puml_id(&format!("{}__{}", owner.path, el.name)),
);
}
}
Comment on lines +169 to +182
boundary_defs.push_str(&format!(
" Component({}, \"{}\", \"{}\", \"{}\")\n",
id, el.name, el.kind, desc
));
for rel in &el.relationships {
let to_id = by_name
.get(rel.target.as_str())
.cloned()
.unwrap_or_else(|| to_puml_id(&rel.target));
rel_defs.push_str(&format!(
"Rel({}, {}, \"{}\", \"{}\")\n",
id, to_id, rel.label, rel.protocol
));
}
Comment on lines 203 to 205
fn to_puml_id(s: &str) -> String {
s.replace('.', "_").replace('/', "_").replace('-', "_")
}
Comment thread adapters/archidoc-rust/src/walker.rs Outdated
Comment on lines +79 to +87
let code_elements = if is_standard_entry {
let dir = path.parent().unwrap_or(path);
read_rs_sources(dir)
.iter()
.flat_map(|(_, src)| parser::extract_code_elements(src))
.collect()
} else {
parser::extract_code_elements(&fs::read_to_string(path).unwrap_or_default())
};
Comment on lines +153 to +157
description: if c.description.is_empty() || c.description == "*No description*" {
None
} else {
Some(c.description.clone())
},
Completes the C4 model downward. Item-level `@c4 code` doc markers turn a
curated set of load-bearing types into code-level nodes under their
component — the rust adapter previously parsed only module `//!` docs.

- archidoc-types: CodeElement on ModuleDoc + ir::CodeElement on DirNode
  (serde-default; existing IR JSON stays valid).
- archidoc-rust/parser: extract_code_elements() uses syn to find
  struct/enum/trait/fn items whose doc contains `@c4 code`; captures kind,
  description, and `@c4 uses` relationships. Unmarked items are ignored
  (curated, not a dump).
- archidoc-rust/walker: aggregates a module's code elements from its
  directory's source files onto the component's ModuleDoc.
- archidoc-engine: ir_builder propagates code_elements; plantuml
  generate_code() renders c4-code.puml (Component per element, kind as the
  tech tag, intra-component `@c4 uses` resolved to qualified ids). Emitted
  only when a code element exists.
- Tests: extract_code_elements curation + typing + relationships.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@nightscape
nightscape force-pushed the feat/c4-code-level branch from 2c24e9c to 3d903a4 Compare June 14, 2026 12:02
…iagram

Auto-detects `impl Trait for Type` blocks and renders an "implements" arrow
from the type to the trait in the `@c4 code` diagram — so the diagram shows
not just which types and traits exist, but which concrete types realize
which traits.

To keep the diagram a curated set, an arrow is drawn only when BOTH ends are
`@c4 code` elements. The walker already filters collected impls to those
whose implementing type is a declared code element (so the IR never carries
Debug/Clone/Serialize noise), and the renderer draws the arrow only when the
trait is a code element too.

- archidoc-types: `TraitImpl { type_name, trait_name }` + `trait_impls` on
  ModuleDoc and DirNode (serde-default, skip-if-empty).
- archidoc-rust/parser: `extract_trait_impls()` via syn (last path segment of
  trait + self type; inherent impls skipped).
- archidoc-rust/walker: collects impls, keeps only those of @C4 code types.
- archidoc-engine: ir_builder + merge propagate the field; plantuml::generate_code
  emits `Rel(type, trait, "implements", "trait")` when both are @C4 code.
- Tests: parser realization extraction + both-are-code render gating.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants