1use crate::detect::DetectorFn;
9use crate::diagram::{
10 BuiltInDiagramSemanticParser, BuiltInRenderSemanticParser, RenderSemanticModel,
11 RenderSemanticParseOutput,
12};
13use crate::{
14 DiagramWarningFact, EditorFamilySemantics, EditorSemanticFacts, EditorSemanticKind, Error,
15 ManagedSemanticJson, OperationControl, OperationControlResult, ParseMetadata, Result,
16};
17use serde::Serialize;
18use serde_json::Value;
19use std::sync::OnceLock;
20
21pub(crate) type CombinedSemanticParser = fn(
22 code: &str,
23 meta: &ParseMetadata,
24 control: &OperationControl,
25) -> OperationControlResult<CombinedSemanticParse>;
26
27pub(crate) type WarningSemanticParser =
28 fn(code: &str, meta: &ParseMetadata) -> Result<WarningSemanticParse>;
29
30pub(crate) struct WarningSemanticParse {
32 model: ManagedSemanticJson,
33 warning_facts: Vec<DiagramWarningFact>,
34}
35
36#[allow(
37 dead_code,
38 reason = "Warning construction is used only by warning-producing diagram families."
39)]
40impl WarningSemanticParse {
41 pub(crate) fn new(model: Value, warning_facts: Vec<DiagramWarningFact>) -> Self {
42 Self {
43 model: model.into(),
44 warning_facts,
45 }
46 }
47
48 pub(crate) fn into_model(self) -> Value {
49 self.model.into_unmanaged_value()
50 }
51
52 pub(crate) fn into_parts(self) -> (ManagedSemanticJson, Vec<DiagramWarningFact>) {
53 (self.model, self.warning_facts)
54 }
55}
56
57pub(crate) struct CombinedSemanticParse {
63 model: Result<ManagedSemanticJson>,
64 editor_facts: EditorSemanticFacts,
65 warning_facts: Vec<DiagramWarningFact>,
66}
67
68#[allow(
70 dead_code,
71 reason = "Shared parser facilities have different consumers in each family selection."
72)]
73pub(crate) struct CombinedSemanticFailure {
74 error: Box<Error>,
75 editor_facts: Box<EditorSemanticFacts>,
76 recovery_parser: Option<&'static str>,
77}
78
79#[allow(
80 dead_code,
81 reason = "Shared parser facilities have different consumers in each family selection."
82)]
83impl CombinedSemanticFailure {
84 pub(crate) fn new(error: Error, editor_facts: EditorSemanticFacts) -> Self {
85 Self {
86 error: Box::new(error),
87 editor_facts: Box::new(editor_facts),
88 recovery_parser: None,
89 }
90 }
91
92 pub(crate) fn parser_recovery(
93 parser: &'static str,
94 error: Error,
95 editor_facts: EditorSemanticFacts,
96 ) -> Self {
97 Self {
98 error: Box::new(error),
99 editor_facts: Box::new(editor_facts),
100 recovery_parser: Some(parser),
101 }
102 }
103
104 pub(crate) fn into_parts(mut self) -> (Error, EditorSemanticFacts) {
105 if let Some(parser) = self.recovery_parser.take() {
106 let (message, span) = match self.error.as_ref() {
107 Error::DiagramParse { diagnostic, .. } => {
108 (diagnostic.message().to_string(), diagnostic.span())
109 }
110 error => (error.to_string(), None),
111 };
112 self.editor_facts.mark_recovered_from_parse_error(
113 format!("{parser} parser recovered after parse error: {message}"),
114 span,
115 );
116 }
117 (*self.error, *self.editor_facts)
118 }
119
120 pub(crate) fn into_error(self) -> Error {
121 *self.error
122 }
123}
124
125#[cfg(test)]
126mod combined_semantic_failure_tests {
127 use super::*;
128 use crate::{EditorSemanticDiagnosticKind, ParseDiagnosticSpanKind, SourceSpan};
129
130 #[test]
131 fn parser_recovery_preserves_the_strict_error_and_exact_editor_diagnostic() {
132 let span = SourceSpan::new(17, 29);
133 let failure = CombinedSemanticFailure::parser_recovery(
134 "quadrant chart",
135 Error::diagram_parse_exact("quadrantChart", "expected point coordinates", span),
136 EditorSemanticFacts::new(),
137 );
138
139 let (error, facts) = failure.into_parts();
140 let Error::DiagramParse {
141 diagram_type,
142 diagnostic,
143 } = error
144 else {
145 panic!("expected diagram parse error");
146 };
147 assert_eq!(diagram_type, "quadrantChart");
148 assert_eq!(diagnostic.message(), "expected point coordinates");
149 assert_eq!(diagnostic.span(), Some(span));
150 assert_eq!(diagnostic.span_kind(), ParseDiagnosticSpanKind::Exact);
151 assert_eq!(facts.diagnostics.len(), 1);
152 assert_eq!(
153 facts.diagnostics[0].message,
154 "quadrant chart parser recovered after parse error: expected point coordinates"
155 );
156 assert_eq!(facts.diagnostics[0].span, Some(span));
157 assert_eq!(
158 facts.diagnostics[0].kind,
159 EditorSemanticDiagnosticKind::ParserRecovery
160 );
161 }
162}
163
164impl CombinedSemanticParse {
165 #[allow(
166 dead_code,
167 reason = "Shared parser facilities have different consumers in each family selection."
168 )]
169 pub(crate) fn from_construction<S, F>(
170 construction: std::result::Result<S, F>,
171 success: impl FnOnce(S) -> (Result<Value>, EditorSemanticFacts),
172 failure: impl FnOnce(F) -> (Error, EditorSemanticFacts),
173 ) -> Self {
174 match construction {
175 Ok(source) => {
176 let (model, editor_facts) = success(source);
177 Self {
178 model: model.map(ManagedSemanticJson::from),
179 editor_facts,
180 warning_facts: Vec::new(),
181 }
182 }
183 Err(parse_failure) => {
184 let (error, editor_facts) = failure(parse_failure);
185 Self {
186 model: Err(error),
187 editor_facts,
188 warning_facts: Vec::new(),
189 }
190 }
191 }
192 }
193
194 #[allow(
195 dead_code,
196 reason = "Shared parser facilities have different consumers in each family selection."
197 )]
198 pub(crate) fn from_construction_with_warning_facts<S, F>(
199 construction: std::result::Result<S, F>,
200 success: impl FnOnce(S) -> (Result<Value>, EditorSemanticFacts, Vec<DiagramWarningFact>),
201 failure: impl FnOnce(F) -> (Error, EditorSemanticFacts),
202 ) -> Self {
203 match construction {
204 Ok(source) => {
205 let (model, editor_facts, warning_facts) = success(source);
206 Self {
207 model: model.map(ManagedSemanticJson::from),
208 editor_facts,
209 warning_facts,
210 }
211 }
212 Err(parse_failure) => {
213 let (error, editor_facts) = failure(parse_failure);
214 Self {
215 model: Err(error),
216 editor_facts,
217 warning_facts: Vec::new(),
218 }
219 }
220 }
221 }
222
223 pub(crate) fn into_parts(
224 self,
225 ) -> (
226 Result<ManagedSemanticJson>,
227 EditorSemanticFacts,
228 Vec<DiagramWarningFact>,
229 ) {
230 (self.model, self.editor_facts, self.warning_facts)
231 }
232}
233
234#[cfg(test)]
235#[allow(
236 dead_code,
237 reason = "Test helpers serve different optional family suites."
238)]
239pub(crate) mod test_support {
240 use super::{CombinedSemanticParse, CombinedSemanticParser};
241 use crate::{
242 EditorSemanticFacts, Error, OperationControl, OperationControlResult, ParseMetadata,
243 };
244 use serde_json::Value;
245
246 pub(crate) fn into_result(
247 parsed: OperationControlResult<CombinedSemanticParse>,
248 ) -> std::result::Result<(Value, EditorSemanticFacts), Error> {
249 let (model, editor_facts, _) = parsed
250 .expect("a private parse control cannot be cancelled")
251 .into_parts();
252 model.map(|model| (model.into_unmanaged_value(), editor_facts))
253 }
254
255 pub(crate) fn editor_facts(
256 parser: CombinedSemanticParser,
257 code: &str,
258 meta: &ParseMetadata,
259 ) -> EditorSemanticFacts {
260 parser(code, meta, &OperationControl::new())
261 .expect("a private parse control cannot be cancelled")
262 .into_parts()
263 .1
264 }
265}
266
267#[derive(Clone, Copy)]
268pub(crate) struct DetectorFact {
269 pub(crate) id: &'static str,
270 pub(crate) detector: DetectorFn,
271}
272
273#[derive(Clone, Copy)]
274pub(crate) struct SemanticParserFact {
275 pub(crate) id: &'static str,
276 pub(crate) parser: BuiltInDiagramSemanticParser,
277}
278
279#[derive(Clone, Copy)]
280pub(crate) struct RenderParserFact {
281 pub(crate) id: &'static str,
282 pub(crate) metadata_id: Option<&'static str>,
283 pub(crate) model_kind: &'static str,
284 pub(crate) parser: BuiltInRenderSemanticParser,
285}
286
287#[derive(Clone, Copy)]
288pub(crate) struct CombinedParserFact {
289 pub(crate) id: &'static str,
290 pub(crate) parser: CombinedSemanticParser,
291}
292
293#[derive(Clone, Copy, Debug, PartialEq, Eq)]
294pub struct DiagramHeaderFact {
295 pub diagram_type: &'static str,
297 pub label: &'static str,
299 pub detail: &'static str,
301}
302
303#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
304#[non_exhaustive]
305pub struct DiagramFamilyCapability {
306 pub diagram_type: &'static str,
308 pub logical_family_kind: &'static str,
310 pub metadata_id: Option<&'static str>,
312 pub render_model_kind: Option<&'static str>,
314 pub has_detector: bool,
316 pub has_semantic_parser: bool,
318 pub has_editor_parser: bool,
320 pub has_combined_parser: bool,
322 pub has_render_parser: bool,
324 pub has_header: bool,
326 pub config_namespace: Option<&'static str>,
328}
329
330#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
334#[non_exhaustive]
335pub struct DiagramFamilySelector {
336 pub logical_family_kind: &'static str,
338 pub feature: &'static str,
340}
341
342#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
347#[non_exhaustive]
348pub struct BuiltInTypedRenderFamily {
349 pub diagram_type: &'static str,
350 pub render_model_kind: &'static str,
351}
352
353#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
359#[serde(transparent)]
360pub struct DiagramFamilyId(&'static str);
361
362impl DiagramFamilyId {
363 pub const FLOWCHART: Self = Self("flowchart");
365
366 pub fn as_str(self) -> &'static str {
367 self.0
368 }
369}
370
371struct FamilyCatalogProjection {
372 detector_facts: Vec<DetectorFact>,
373 semantic_parser_facts: Vec<SemanticParserFact>,
374 render_parser_facts: Vec<RenderParserFact>,
375 combined_parser_facts: Vec<CombinedParserFact>,
376 supported_diagram_metadata_ids: Vec<&'static str>,
377 diagram_header_facts: Vec<DiagramHeaderFact>,
378 diagram_family_capabilities: Vec<DiagramFamilyCapability>,
379 built_in_typed_render_families: Vec<BuiltInTypedRenderFamily>,
380}
381
382impl FamilyCatalogProjection {
383 fn build<'a>(
384 variants: impl IntoIterator<Item = (&'a DiagramFamilyDefinition, &'a FamilyVariantDefinition)>,
385 ) -> Self {
386 let mut detector_facts = Vec::<(u16, DetectorFact)>::new();
387 let mut semantic_parser_facts = Vec::<(u16, SemanticParserFact)>::new();
388 let mut render_parser_facts = Vec::<(u16, RenderParserFact)>::new();
389 let mut combined_parser_facts = Vec::<(u16, CombinedParserFact)>::new();
390 let mut metadata_facts = Vec::<(u16, &'static str)>::new();
391 let mut diagram_header_facts = Vec::<(u16, DiagramHeaderFact)>::new();
392 let mut diagram_family_capabilities = Vec::<(u16, DiagramFamilyCapability)>::new();
393
394 for (family, variant) in variants {
395 let identity = &variant.identity;
396 let implementation = &variant.implementation;
397 if let Some(ordered) = identity.detector {
398 detector_facts.push((
399 ordered.order,
400 DetectorFact {
401 id: identity.id,
402 detector: ordered.value,
403 },
404 ));
405 }
406 if let Some(ordered) = implementation.semantic {
407 semantic_parser_facts.push((
408 ordered.order,
409 SemanticParserFact {
410 id: identity.id,
411 parser: ordered.value,
412 },
413 ));
414 }
415 if let Some(ordered) = implementation.typed_render {
416 render_parser_facts.push((
417 ordered.order,
418 RenderParserFact {
419 id: identity.id,
420 metadata_id: identity.metadata.map(|metadata| metadata.id),
421 model_kind: identity
422 .render_model_kind
423 .expect("typed render variants declare their model kind"),
424 parser: ordered.value,
425 },
426 ));
427 }
428 if let Some(ordered) = implementation.combined {
429 combined_parser_facts.push((
430 ordered.order,
431 CombinedParserFact {
432 id: identity.id,
433 parser: ordered.value,
434 },
435 ));
436 }
437 if let Some((order, id)) = identity
438 .metadata
439 .and_then(|metadata| metadata.order.map(|order| (order, metadata.id)))
440 {
441 metadata_facts.push((order, id));
442 }
443 for header in identity.headers {
444 diagram_header_facts.push((
445 header.order,
446 DiagramHeaderFact {
447 diagram_type: identity.id,
448 label: header.label,
449 detail: header.detail,
450 },
451 ));
452 }
453 diagram_family_capabilities.push((
454 identity.catalog_order,
455 DiagramFamilyCapability {
456 diagram_type: identity.id,
457 logical_family_kind: family.logical_kind,
458 metadata_id: identity.metadata.map(|metadata| metadata.id),
459 render_model_kind: identity.render_model_kind,
460 has_detector: identity.detector.is_some(),
461 has_semantic_parser: implementation.semantic.is_some(),
462 has_editor_parser: implementation.combined.is_some(),
463 has_combined_parser: implementation.combined.is_some(),
464 has_render_parser: implementation.typed_render.is_some(),
465 has_header: !identity.headers.is_empty(),
466 config_namespace: family.config.map(|config| config.namespace),
467 },
468 ));
469 }
470
471 let detector_facts = ordered_values(detector_facts);
472 let semantic_parser_facts = ordered_values(semantic_parser_facts);
473 let render_parser_facts = ordered_values(render_parser_facts);
474 let combined_parser_facts = ordered_values(combined_parser_facts);
475 let metadata_facts = ordered_values(metadata_facts);
476 let diagram_header_facts = ordered_values(diagram_header_facts);
477 let diagram_family_capabilities = ordered_values(diagram_family_capabilities);
478 let supported_diagram_metadata_ids = metadata_facts
479 .iter()
480 .copied()
481 .filter(|metadata_id| {
482 diagram_family_capabilities
483 .iter()
484 .any(|fact| fact.metadata_id == Some(*metadata_id) && fact.has_semantic_parser)
485 })
486 .collect::<Vec<&'static str>>();
487 let mut built_in_typed_render_families = Vec::<BuiltInTypedRenderFamily>::new();
488 for metadata_id in metadata_facts {
489 let Some(fact) = render_parser_facts
490 .iter()
491 .find(|fact| fact.metadata_id == Some(metadata_id))
492 else {
493 continue;
494 };
495 if !built_in_typed_render_families
496 .iter()
497 .any(|family| family.render_model_kind == fact.model_kind)
498 {
499 built_in_typed_render_families.push(BuiltInTypedRenderFamily {
500 diagram_type: metadata_id,
501 render_model_kind: fact.model_kind,
502 });
503 }
504 }
505
506 Self {
507 detector_facts,
508 semantic_parser_facts,
509 render_parser_facts,
510 combined_parser_facts,
511 supported_diagram_metadata_ids,
512 diagram_header_facts,
513 diagram_family_capabilities,
514 built_in_typed_render_families,
515 }
516 }
517}
518
519fn ordered_values<T>(mut values: Vec<(u16, T)>) -> Vec<T> {
520 values.sort_by_key(|(order, _)| *order);
521 values.into_iter().map(|(_, value)| value).collect()
522}
523
524fn family_catalog_projection() -> &'static FamilyCatalogProjection {
525 static CATALOG: OnceLock<FamilyCatalogProjection> = OnceLock::new();
526 CATALOG.get_or_init(|| FamilyCatalogProjection::build(variants()))
527}
528
529pub(crate) fn detector_facts() -> &'static [DetectorFact] {
530 family_catalog_projection().detector_facts.as_slice()
531}
532
533pub(crate) fn semantic_parser_facts() -> &'static [SemanticParserFact] {
534 family_catalog_projection().semantic_parser_facts.as_slice()
535}
536
537pub(crate) fn render_parser_facts() -> &'static [RenderParserFact] {
538 family_catalog_projection().render_parser_facts.as_slice()
539}
540
541pub(crate) fn combined_parser_facts() -> &'static [CombinedParserFact] {
542 family_catalog_projection().combined_parser_facts.as_slice()
543}
544
545pub(crate) fn combined_parser(diagram_type: &str) -> Option<CombinedSemanticParser> {
546 combined_parser_facts()
547 .iter()
548 .find_map(|fact| (fact.id == diagram_type).then_some(fact.parser))
549}
550
551pub(crate) fn warning_semantic_parser(diagram_type: &str) -> Option<WarningSemanticParser> {
552 find_variant(diagram_type).and_then(|(_, variant)| variant.implementation.warning_semantic)
553}
554
555pub(crate) fn supported_diagram_metadata_ids() -> &'static [&'static str] {
556 family_catalog_projection()
557 .supported_diagram_metadata_ids
558 .as_slice()
559}
560
561pub(crate) fn diagram_header_facts() -> &'static [DiagramHeaderFact] {
562 family_catalog_projection().diagram_header_facts.as_slice()
563}
564
565pub(crate) fn diagram_family_capabilities() -> &'static [DiagramFamilyCapability] {
566 family_catalog_projection()
567 .diagram_family_capabilities
568 .as_slice()
569}
570
571pub(crate) fn diagram_family_selectors() -> &'static [DiagramFamilySelector] {
572 static SELECTORS: OnceLock<Vec<DiagramFamilySelector>> = OnceLock::new();
573 SELECTORS.get_or_init(|| {
574 FAMILY_CATALOG
575 .iter()
576 .filter_map(|family| {
577 family.selector.map(|feature| DiagramFamilySelector {
578 logical_family_kind: family.logical_kind,
579 feature,
580 })
581 })
582 .collect()
583 })
584}
585
586pub(crate) fn built_in_typed_render_families() -> &'static [BuiltInTypedRenderFamily] {
587 family_catalog_projection()
588 .built_in_typed_render_families
589 .as_slice()
590}
591
592pub(crate) fn is_builtin_diagram_type(diagram_type: &str) -> bool {
593 find_variant(diagram_type).is_some()
594}
595
596pub(crate) fn render_model_kind_supports_diagram_type(
597 model_kind: &'static str,
598 diagram_type: &str,
599) -> bool {
600 render_parser_facts()
601 .iter()
602 .any(|fact| fact.id == diagram_type && fact.model_kind == model_kind)
603}
604
605pub fn diagram_type_family_kind(diagram_type: &str) -> Option<&'static str> {
606 diagram_type_family_id(diagram_type).map(DiagramFamilyId::as_str)
607}
608
609pub fn diagram_type_metadata_id(diagram_type: &str) -> Option<&'static str> {
610 find_variant(diagram_type)
611 .and_then(|(_, variant)| variant.identity.metadata.map(|metadata| metadata.id))
612}
613
614pub fn diagram_type_family_id(diagram_type: &str) -> Option<DiagramFamilyId> {
615 find_variant(diagram_type).map(|(family, _)| DiagramFamilyId(family.logical_kind))
616}
617
618pub(crate) fn diagram_type_editor_semantics(diagram_type: &str) -> Option<EditorFamilySemantics> {
619 find_variant(diagram_type).map(|(family, _)| family.editor_semantics)
620}
621
622pub fn diagram_type_render_model_kind(diagram_type: &str) -> Option<&'static str> {
623 find_variant(diagram_type).and_then(|(_, variant)| variant.identity.render_model_kind)
624}
625
626macro_rules! render_parser {
627 ($fn_name:ident, $parser:path, $variant:path) => {
628 fn $fn_name(
629 code: &str,
630 meta: &ParseMetadata,
631 control: &OperationControl,
632 ) -> OperationControlResult<Result<RenderSemanticParseOutput>> {
633 control.checkpoint()?;
634 let result = $parser(code, meta)
635 .map($variant)
636 .map(RenderSemanticParseOutput::new);
637 control.checkpoint()?;
638 Ok(result)
639 }
640 };
641}
642
643#[allow(
644 unused_macros,
645 reason = "No controlled family adapter is emitted in infrastructure-only builds."
646)]
647macro_rules! render_parser_controlled {
648 ($fn_name:ident, $parser:path, $variant:path) => {
649 fn $fn_name(
650 code: &str,
651 meta: &ParseMetadata,
652 control: &OperationControl,
653 ) -> OperationControlResult<Result<RenderSemanticParseOutput>> {
654 control.checkpoint()?;
655 let result = $parser(code, meta, control)?
656 .map($variant)
657 .map(RenderSemanticParseOutput::new);
658 control.checkpoint()?;
659 Ok(result)
660 }
661 };
662}
663
664render_parser!(
665 render_error,
666 crate::diagrams::error_diagram::parse_error_model_for_render,
667 RenderSemanticModel::Error
668);
669#[cfg(feature = "diagram-mindmap")]
670render_parser_controlled!(
671 render_mindmap,
672 crate::diagrams::mindmap::parse_mindmap_model_for_render_controlled,
673 RenderSemanticModel::Mindmap
674);
675#[cfg(feature = "diagram-state")]
676render_parser_controlled!(
677 render_state,
678 crate::diagrams::state::parse_state_model_for_render_controlled,
679 RenderSemanticModel::State
680);
681#[cfg(feature = "diagram-zenuml")]
682render_parser_controlled!(
683 render_zenuml,
684 crate::diagrams::zenuml::parse_zenuml_model_for_render_controlled,
685 RenderSemanticModel::Zenuml
686);
687#[cfg(feature = "diagram-sequence")]
688render_parser_controlled!(
689 render_sequence,
690 crate::diagrams::sequence::parse_sequence_model_for_render_controlled,
691 RenderSemanticModel::Sequence
692);
693#[cfg(any(feature = "diagram-flowchart", feature = "diagram-swimlane"))]
694fn render_flowchart(
695 code: &str,
696 meta: &ParseMetadata,
697 control: &OperationControl,
698) -> OperationControlResult<Result<RenderSemanticParseOutput>> {
699 let result = crate::diagrams::flowchart::parse_flowchart_model_with_render_context_controlled(
700 code, meta, control,
701 )?;
702 Ok(result
703 .map(|(model, label_sources)| RenderSemanticParseOutput::flowchart(model, label_sources)))
704}
705#[cfg(feature = "diagram-class")]
706render_parser_controlled!(
707 render_class,
708 crate::diagrams::class::parse_class_typed_controlled,
709 RenderSemanticModel::Class
710);
711#[cfg(feature = "diagram-c4")]
712render_parser_controlled!(
713 render_c4,
714 crate::diagrams::c4::parse_c4_model_for_render_controlled,
715 RenderSemanticModel::C4
716);
717#[cfg(feature = "diagram-cynefin")]
718render_parser_controlled!(
719 render_cynefin,
720 crate::diagrams::cynefin::parse_cynefin_model_for_render_controlled,
721 RenderSemanticModel::Cynefin
722);
723#[cfg(feature = "diagram-railroad")]
724render_parser_controlled!(
725 render_railroad,
726 crate::diagrams::railroad::parse_railroad_model_for_render_controlled,
727 RenderSemanticModel::Railroad
728);
729#[cfg(feature = "diagram-railroad")]
730render_parser_controlled!(
731 render_railroad_ebnf,
732 crate::diagrams::railroad::parse_railroad_ebnf_model_for_render_controlled,
733 RenderSemanticModel::Railroad
734);
735#[cfg(feature = "diagram-railroad")]
736render_parser_controlled!(
737 render_railroad_abnf,
738 crate::diagrams::railroad::parse_railroad_abnf_model_for_render_controlled,
739 RenderSemanticModel::Railroad
740);
741#[cfg(feature = "diagram-railroad")]
742render_parser_controlled!(
743 render_railroad_peg,
744 crate::diagrams::railroad::parse_railroad_peg_model_for_render_controlled,
745 RenderSemanticModel::Railroad
746);
747#[cfg(feature = "diagram-architecture")]
748render_parser_controlled!(
749 render_architecture,
750 crate::diagrams::architecture::parse_architecture_model_for_render_controlled,
751 RenderSemanticModel::Architecture
752);
753#[cfg(feature = "diagram-kanban")]
754render_parser_controlled!(
755 render_kanban,
756 crate::diagrams::kanban::parse_kanban_model_for_render_controlled,
757 RenderSemanticModel::Kanban
758);
759#[cfg(feature = "diagram-gantt")]
760render_parser_controlled!(
761 render_gantt,
762 crate::diagrams::gantt::parse_gantt_model_for_render_controlled,
763 RenderSemanticModel::Gantt
764);
765#[cfg(feature = "diagram-pie")]
766render_parser_controlled!(
767 render_pie,
768 crate::diagrams::pie::parse_pie_model_for_render_controlled,
769 RenderSemanticModel::Pie
770);
771#[cfg(feature = "diagram-packet")]
772render_parser_controlled!(
773 render_packet,
774 crate::diagrams::packet::parse_packet_model_for_render_controlled,
775 RenderSemanticModel::Packet
776);
777#[cfg(feature = "diagram-timeline")]
778render_parser_controlled!(
779 render_timeline,
780 crate::diagrams::timeline::parse_timeline_model_for_render_controlled,
781 RenderSemanticModel::Timeline
782);
783#[cfg(feature = "diagram-journey")]
784render_parser_controlled!(
785 render_journey,
786 crate::diagrams::journey::parse_journey_model_for_render_controlled,
787 RenderSemanticModel::Journey
788);
789#[cfg(feature = "diagram-requirement")]
790render_parser_controlled!(
791 render_requirement,
792 crate::diagrams::requirement::parse_requirement_model_for_render_controlled,
793 RenderSemanticModel::Requirement
794);
795#[cfg(feature = "diagram-sankey")]
796render_parser_controlled!(
797 render_sankey,
798 crate::diagrams::sankey::parse_sankey_model_for_render_controlled,
799 RenderSemanticModel::Sankey
800);
801#[cfg(feature = "diagram-radar")]
802render_parser_controlled!(
803 render_radar,
804 crate::diagrams::radar::parse_radar_model_for_render_controlled,
805 RenderSemanticModel::Radar
806);
807#[cfg(feature = "diagram-info")]
808render_parser_controlled!(
809 render_info,
810 crate::diagrams::info::parse_info_model_for_render_controlled,
811 RenderSemanticModel::Info
812);
813#[cfg(feature = "diagram-treemap")]
814render_parser_controlled!(
815 render_treemap,
816 crate::diagrams::treemap::parse_treemap_model_for_render_controlled,
817 RenderSemanticModel::Treemap
818);
819#[cfg(feature = "diagram-block")]
820render_parser_controlled!(
821 render_block,
822 crate::diagrams::block::parse_block_model_for_render_controlled,
823 RenderSemanticModel::Block
824);
825#[cfg(feature = "diagram-er")]
826render_parser_controlled!(
827 render_er,
828 crate::diagrams::er::parse_er_model_for_render_controlled,
829 RenderSemanticModel::Er
830);
831#[cfg(feature = "diagram-quadrant-chart")]
832render_parser_controlled!(
833 render_quadrant_chart,
834 crate::diagrams::quadrant_chart::parse_quadrant_chart_model_for_render_controlled,
835 RenderSemanticModel::QuadrantChart
836);
837#[cfg(feature = "diagram-xychart")]
838render_parser_controlled!(
839 render_xychart,
840 crate::diagrams::xychart::parse_xychart_model_for_render_controlled,
841 RenderSemanticModel::XyChart
842);
843#[cfg(feature = "diagram-git-graph")]
844render_parser_controlled!(
845 render_git_graph,
846 crate::diagrams::git_graph::parse_git_graph_model_for_render_controlled,
847 RenderSemanticModel::GitGraph
848);
849#[cfg(feature = "diagram-tree-view")]
850render_parser_controlled!(
851 render_tree_view,
852 crate::diagrams::tree_view::parse_tree_view_model_for_render_controlled,
853 RenderSemanticModel::TreeView
854);
855#[cfg(feature = "diagram-ishikawa")]
856render_parser_controlled!(
857 render_ishikawa,
858 crate::diagrams::ishikawa::parse_ishikawa_model_for_render_controlled,
859 RenderSemanticModel::Ishikawa
860);
861#[cfg(feature = "diagram-event-modeling")]
862render_parser_controlled!(
863 render_eventmodeling,
864 crate::diagrams::eventmodeling::parse_eventmodeling_model_for_render_controlled,
865 RenderSemanticModel::EventModeling
866);
867#[cfg(feature = "diagram-venn")]
868render_parser_controlled!(
869 render_venn,
870 crate::diagrams::venn::parse_venn_model_for_render_controlled,
871 RenderSemanticModel::Venn
872);
873#[cfg(feature = "diagram-wardley")]
874render_parser_controlled!(
875 render_wardley,
876 crate::diagrams::wardley::parse_wardley_model_for_render_controlled,
877 RenderSemanticModel::Wardley
878);
879#[cfg(feature = "diagram-usecase")]
880render_parser_controlled!(
881 render_usecase,
882 crate::diagrams::usecase::parse_usecase_model_for_render_controlled,
883 RenderSemanticModel::Usecase
884);
885#[cfg(feature = "diagram-agentflow")]
886render_parser_controlled!(
887 render_agentflow,
888 crate::diagrams::agentflow::parse_agentflow_model_for_render_controlled,
889 RenderSemanticModel::Agentflow
890);
891
892#[derive(Clone, Copy)]
893struct Ordered<T> {
894 order: u16,
895 value: T,
896}
897
898const fn ordered<T>(order: u16, value: T) -> Ordered<T> {
899 Ordered { order, value }
900}
901
902#[derive(Clone, Copy)]
903struct MetadataDefinition {
904 id: &'static str,
905 order: Option<u16>,
906}
907
908const fn metadata(id: &'static str, order: Option<u16>) -> MetadataDefinition {
909 MetadataDefinition { id, order }
910}
911
912#[derive(Clone, Copy)]
913struct HeaderDefinition {
914 order: u16,
915 label: &'static str,
916 detail: &'static str,
917}
918
919const fn header(order: u16, label: &'static str, detail: &'static str) -> HeaderDefinition {
920 HeaderDefinition {
921 order,
922 label,
923 detail,
924 }
925}
926
927#[derive(Clone, Copy)]
928struct FamilyVariantDefinition {
929 identity: FamilyVariantIdentity,
930 implementation: FamilyImplementation,
931}
932
933#[derive(Clone, Copy)]
935struct FamilyVariantIdentity {
936 id: &'static str,
937 catalog_order: u16,
938 detector: Option<Ordered<DetectorFn>>,
939 render_model_kind: Option<&'static str>,
940 metadata: Option<MetadataDefinition>,
941 headers: &'static [HeaderDefinition],
942 frontmatter_alias_order: Option<u16>,
943}
944
945#[derive(Clone, Copy, Default)]
950struct FamilyImplementation {
951 semantic: Option<Ordered<BuiltInDiagramSemanticParser>>,
952 warning_semantic: Option<WarningSemanticParser>,
953 combined: Option<Ordered<CombinedSemanticParser>>,
954 typed_render: Option<Ordered<BuiltInRenderSemanticParser>>,
955}
956
957#[derive(Clone, Copy)]
958struct FamilyConfigDefinition {
959 namespace: &'static str,
960 frontmatter_order: u16,
961}
962
963#[derive(Clone, Copy)]
964struct DiagramFamilyDefinition {
965 logical_kind: &'static str,
966 selector: Option<&'static str>,
967 editor_semantics: EditorFamilySemantics,
968 config: Option<FamilyConfigDefinition>,
969 variants: &'static [FamilyVariantDefinition],
970}
971
972const GENERIC_EDITOR_SEMANTICS: EditorFamilySemantics =
973 EditorFamilySemantics::new(EditorSemanticKind::Variable);
974const FLOWCHART_EDITOR_SEMANTICS: EditorFamilySemantics =
975 EditorFamilySemantics::new(EditorSemanticKind::Module);
976const SWIMLANE_EDITOR_SEMANTICS: EditorFamilySemantics =
977 EditorFamilySemantics::new(EditorSemanticKind::Variable);
978const MINDMAP_EDITOR_SEMANTICS: EditorFamilySemantics =
979 EditorFamilySemantics::new(EditorSemanticKind::Namespace);
980const SEQUENCE_EDITOR_SEMANTICS: EditorFamilySemantics =
981 EditorFamilySemantics::new(EditorSemanticKind::Event);
982const CLASS_EDITOR_SEMANTICS: EditorFamilySemantics =
983 EditorFamilySemantics::new(EditorSemanticKind::Class);
984const ER_EDITOR_SEMANTICS: EditorFamilySemantics =
985 EditorFamilySemantics::new(EditorSemanticKind::Struct);
986const CARDINAL_EDITOR_SEMANTICS: EditorFamilySemantics =
987 EditorFamilySemantics::new(EditorSemanticKind::Variable);
988const STATE_EDITOR_SEMANTICS: EditorFamilySemantics =
989 EditorFamilySemantics::new(EditorSemanticKind::Class);
990const BLOCK_EDITOR_SEMANTICS: EditorFamilySemantics =
991 EditorFamilySemantics::new(EditorSemanticKind::Object);
992
993macro_rules! variant {
994 (
995 $(feature: $feature:literal,)?
996 id: $id:literal,
997 catalog_order: $catalog_order:literal,
998 detector: $detector:expr,
999 semantic: $semantic:expr,
1000 $(warning_semantic: $warning_semantic:expr,)?
1001 combined: $combined:expr,
1002 typed: $typed:expr,
1003 render_kind: $render_kind:expr,
1004 metadata: $metadata:expr,
1005 headers: $headers:expr,
1006 config_alias_order: $config_alias_order:expr $(,)?
1007 ) => {
1008 FamilyVariantDefinition {
1009 identity: FamilyVariantIdentity {
1010 id: $id,
1011 catalog_order: $catalog_order,
1012 detector: $detector,
1013 render_model_kind: $render_kind,
1014 metadata: $metadata,
1015 headers: $headers,
1016 frontmatter_alias_order: $config_alias_order,
1017 },
1018 implementation: {
1019 $(#[cfg(feature = $feature)])?
1020 {
1021 FamilyImplementation {
1022 semantic: $semantic,
1023 warning_semantic: variant!(@warning_semantic $($warning_semantic)?),
1024 combined: $combined,
1025 typed_render: $typed,
1026 }
1027 }
1028 $(#[cfg(not(feature = $feature))]
1029 {
1030 FamilyImplementation {
1031 semantic: None,
1032 warning_semantic: None,
1033 combined: None,
1034 typed_render: None,
1035 }
1036 })?
1037 },
1038 }
1039 };
1040 (@warning_semantic) => {
1041 None
1042 };
1043 (@warning_semantic $warning_semantic:expr) => {
1044 Some($warning_semantic)
1045 };
1046}
1047
1048fn variants() -> impl Iterator<
1049 Item = (
1050 &'static DiagramFamilyDefinition,
1051 &'static FamilyVariantDefinition,
1052 ),
1053> {
1054 FAMILY_CATALOG
1055 .iter()
1056 .flat_map(|family| family.variants.iter().map(move |variant| (family, variant)))
1057}
1058
1059fn find_variant(
1060 diagram_type: &str,
1061) -> Option<(
1062 &'static DiagramFamilyDefinition,
1063 &'static FamilyVariantDefinition,
1064)> {
1065 FAMILY_CATALOG.iter().find_map(|family| {
1066 family
1067 .variants
1068 .iter()
1069 .find(|variant| variant.identity.id == diagram_type)
1070 .map(|variant| (family, variant))
1071 })
1072}
1073
1074#[derive(Clone, Copy)]
1075pub(crate) struct FrontmatterConfigAliasFact {
1076 pub(crate) source: &'static str,
1077 pub(crate) namespace: &'static str,
1078}
1079
1080pub(crate) fn frontmatter_config_aliases() -> &'static [FrontmatterConfigAliasFact] {
1081 static FACTS: OnceLock<Vec<FrontmatterConfigAliasFact>> = OnceLock::new();
1082 FACTS
1083 .get_or_init(|| {
1084 let mut facts: Vec<_> = FAMILY_CATALOG
1085 .iter()
1086 .flat_map(|family| {
1087 family.variants.iter().filter_map(move |variant| {
1088 variant.identity.frontmatter_alias_order.map(|order| {
1089 let namespace = family
1090 .config
1091 .expect("config aliases require a family namespace")
1092 .namespace;
1093 (
1094 order,
1095 FrontmatterConfigAliasFact {
1096 source: variant.identity.id,
1097 namespace,
1098 },
1099 )
1100 })
1101 })
1102 })
1103 .collect();
1104 facts.sort_by_key(|(order, _)| *order);
1105 facts.into_iter().map(|(_, fact)| fact).collect()
1106 })
1107 .as_slice()
1108}
1109
1110pub(crate) fn frontmatter_config_namespaces() -> &'static [&'static str] {
1111 static NAMESPACES: OnceLock<Vec<&'static str>> = OnceLock::new();
1112 NAMESPACES
1113 .get_or_init(|| {
1114 let mut namespaces: Vec<_> = FAMILY_CATALOG
1115 .iter()
1116 .filter_map(|family| {
1117 family
1118 .config
1119 .map(|config| (config.frontmatter_order, config.namespace))
1120 })
1121 .collect();
1122 namespaces.sort_by_key(|(order, _)| *order);
1123 namespaces
1124 .into_iter()
1125 .map(|(_, namespace)| namespace)
1126 .collect()
1127 })
1128 .as_slice()
1129}
1130
1131pub(crate) fn config_namespace_for_diagram_type(diagram_type: &str) -> Option<&'static str> {
1132 find_variant(diagram_type).and_then(|(family, _)| family.config.map(|config| config.namespace))
1133}
1134
1135const FLOWCHART_HEADERS: &[HeaderDefinition] = &[
1136 header(0, "flowchart TD", "flowchart header"),
1137 header(1, "graph TD", "flowchart alias"),
1138];
1139const SEQUENCE_HEADERS: &[HeaderDefinition] = &[header(2, "sequenceDiagram", "sequence header")];
1140const SWIMLANE_HEADERS: &[HeaderDefinition] = &[header(3, "swimlane-beta", "swimlane header")];
1141const CLASS_HEADERS: &[HeaderDefinition] = &[
1142 header(4, "classDiagram", "class header"),
1143 header(5, "classDiagram-v2", "class header"),
1144];
1145const STATE_HEADERS: &[HeaderDefinition] = &[
1146 header(6, "stateDiagram-v2", "state header"),
1147 header(7, "stateDiagram", "legacy state header"),
1148];
1149const ER_HEADERS: &[HeaderDefinition] = &[header(8, "erDiagram", "er header")];
1150const GANTT_HEADERS: &[HeaderDefinition] = &[header(9, "gantt", "gantt header")];
1151const MINDMAP_HEADERS: &[HeaderDefinition] = &[header(10, "mindmap", "mindmap header")];
1152const INFO_HEADERS: &[HeaderDefinition] = &[header(11, "info", "info header")];
1153const JOURNEY_HEADERS: &[HeaderDefinition] = &[header(12, "journey", "journey header")];
1154const TIMELINE_HEADERS: &[HeaderDefinition] = &[header(13, "timeline", "timeline header")];
1155const GIT_GRAPH_HEADERS: &[HeaderDefinition] = &[header(14, "gitGraph", "git graph header")];
1156const PIE_HEADERS: &[HeaderDefinition] = &[header(15, "pie", "pie header")];
1157const REQUIREMENT_HEADERS: &[HeaderDefinition] =
1158 &[header(16, "requirementDiagram", "requirement header")];
1159const SANKEY_HEADERS: &[HeaderDefinition] = &[header(17, "sankey", "sankey header")];
1160const PACKET_HEADERS: &[HeaderDefinition] = &[
1161 header(18, "packet", "packet header"),
1162 header(19, "packet-beta", "packet beta header"),
1163];
1164const XYCHART_HEADERS: &[HeaderDefinition] = &[
1165 header(20, "xychart", "xychart header"),
1166 header(21, "xychart-beta", "xychart beta header"),
1167];
1168const TREE_VIEW_HEADERS: &[HeaderDefinition] = &[header(22, "treeView-beta", "tree view header")];
1169const ISHIKAWA_HEADERS: &[HeaderDefinition] = &[header(23, "ishikawa-beta", "ishikawa header")];
1170const EVENTMODELING_HEADERS: &[HeaderDefinition] =
1171 &[header(24, "eventmodeling", "event modeling header")];
1172const QUADRANT_HEADERS: &[HeaderDefinition] =
1173 &[header(25, "quadrantChart", "quadrant chart header")];
1174const VENN_HEADERS: &[HeaderDefinition] = &[header(26, "venn-beta", "venn header")];
1175const ZENUML_HEADERS: &[HeaderDefinition] = &[header(27, "zenuml", "zenuml header")];
1176const C4_HEADERS: &[HeaderDefinition] = &[
1177 header(28, "C4Context", "c4 context header"),
1178 header(29, "C4Container", "c4 container header"),
1179 header(30, "C4Component", "c4 component header"),
1180 header(31, "C4Dynamic", "c4 dynamic header"),
1181 header(32, "C4Deployment", "c4 deployment header"),
1182];
1183const KANBAN_HEADERS: &[HeaderDefinition] = &[header(33, "kanban", "kanban header")];
1184const ARCHITECTURE_HEADERS: &[HeaderDefinition] =
1185 &[header(34, "architecture-beta", "architecture header")];
1186const BLOCK_HEADERS: &[HeaderDefinition] = &[header(35, "block-beta", "block header")];
1187const RADAR_HEADERS: &[HeaderDefinition] = &[header(36, "radar-beta", "radar header")];
1188const TREEMAP_HEADERS: &[HeaderDefinition] = &[header(37, "treemap-beta", "treemap header")];
1189const RAILROAD_HEADERS: &[HeaderDefinition] = &[header(38, "railroad-beta", "railroad header")];
1190const RAILROAD_EBNF_HEADERS: &[HeaderDefinition] =
1191 &[header(39, "railroad-ebnf-beta", "railroad ebnf header")];
1192const RAILROAD_ABNF_HEADERS: &[HeaderDefinition] =
1193 &[header(40, "railroad-abnf-beta", "railroad abnf header")];
1194const RAILROAD_PEG_HEADERS: &[HeaderDefinition] =
1195 &[header(41, "railroad-peg-beta", "railroad peg header")];
1196const WARDLEY_HEADERS: &[HeaderDefinition] = &[header(42, "wardley-beta", "wardley header")];
1197const CYNEFIN_HEADERS: &[HeaderDefinition] = &[header(43, "cynefin-beta", "cynefin header")];
1198const FLOWCHART_ELK_HEADERS: &[HeaderDefinition] =
1199 &[header(44, "flowchart-elk TD", "elk flowchart header")];
1200const USECASE_HEADERS: &[HeaderDefinition] =
1201 &[header(45, "usecase-beta", "usecase diagram header")];
1202const AGENTFLOW_HEADERS: &[HeaderDefinition] =
1203 &[header(46, "agentflow-beta", "agentflow diagram header")];
1204
1205const ERROR_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1206 id: "error",
1207 catalog_order: 0,
1208 detector: Some(ordered(0, crate::detect::detector_error)),
1209 semantic: Some(ordered(0, crate::diagrams::error_diagram::parse_error)),
1210 combined: None,
1211 typed: Some(ordered(38, render_error)),
1212 render_kind: Some("error"),
1213 metadata: None,
1214 headers: &[],
1215 config_alias_order: None,
1216}];
1217
1218const FLOWCHART_VARIANTS: &[FamilyVariantDefinition] = &[
1219 variant! {
1220 feature: "diagram-flowchart",
1221 id: "flowchart-elk",
1222 catalog_order: 2,
1223 detector: Some(ordered(2, crate::detect::detector_flowchart_elk)),
1224 semantic: Some(ordered(3, crate::diagrams::flowchart::parse_flowchart)),
1225 warning_semantic: crate::diagrams::flowchart::parse_flowchart_with_warning_facts,
1226 combined: Some(ordered(2, crate::diagrams::flowchart::parse_flowchart_json_and_editor_facts)),
1227 typed: Some(ordered(7, render_flowchart)),
1228 render_kind: Some("flowchart"),
1229 metadata: Some(metadata("flowchart", None)),
1230 headers: FLOWCHART_ELK_HEADERS,
1231 config_alias_order: Some(3),
1232 },
1233 variant! {
1234 feature: "diagram-flowchart",
1235 id: "flowchart-v2",
1236 catalog_order: 17,
1237 detector: Some(ordered(17, crate::detect::detector_flowchart_v2)),
1238 semantic: Some(ordered(1, crate::diagrams::flowchart::parse_flowchart)),
1239 warning_semantic: crate::diagrams::flowchart::parse_flowchart_with_warning_facts,
1240 combined: Some(ordered(0, crate::diagrams::flowchart::parse_flowchart_json_and_editor_facts)),
1241 typed: Some(ordered(5, render_flowchart)),
1242 render_kind: Some("flowchart"),
1243 metadata: Some(metadata("flowchart", Some(7))),
1244 headers: FLOWCHART_HEADERS,
1245 config_alias_order: Some(2),
1246 },
1247 variant! {
1248 feature: "diagram-flowchart",
1249 id: "flowchart",
1250 catalog_order: 18,
1251 detector: None,
1252 semantic: Some(ordered(2, crate::diagrams::flowchart::parse_flowchart)),
1253 warning_semantic: crate::diagrams::flowchart::parse_flowchart_with_warning_facts,
1254 combined: Some(ordered(1, crate::diagrams::flowchart::parse_flowchart_json_and_editor_facts)),
1255 typed: Some(ordered(6, render_flowchart)),
1256 render_kind: Some("flowchart"),
1257 metadata: Some(metadata("flowchart", None)),
1258 headers: &[],
1259 config_alias_order: None,
1260 },
1261];
1262
1263const SWIMLANE_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1264 feature: "diagram-swimlane",
1265 id: "swimlane",
1266 catalog_order: 16,
1267 detector: Some(ordered(16, crate::detect::detector_swimlane)),
1268 semantic: Some(ordered(9, crate::diagrams::flowchart::parse_flowchart)),
1269 warning_semantic: crate::diagrams::flowchart::parse_flowchart_with_warning_facts,
1270 combined: Some(ordered(3, crate::diagrams::flowchart::parse_flowchart_json_and_editor_facts)),
1271 typed: Some(ordered(39, render_flowchart)),
1272 render_kind: Some("flowchart"),
1273 metadata: Some(metadata("swimlane", Some(27))),
1274 headers: SWIMLANE_HEADERS,
1275 config_alias_order: None,
1276}];
1277
1278const MINDMAP_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1279 feature: "diagram-mindmap",
1280 id: "mindmap",
1281 catalog_order: 3,
1282 detector: Some(ordered(3, crate::detect::detector_mindmap)),
1283 semantic: Some(ordered(22, crate::diagrams::mindmap::parse_mindmap)),
1284 combined: Some(ordered(5, crate::diagrams::mindmap::parse_mindmap_json_and_editor_facts)),
1285 typed: Some(ordered(0, render_mindmap)),
1286 render_kind: Some("mindmap"),
1287 metadata: Some(metadata("mindmap", Some(14))),
1288 headers: MINDMAP_HEADERS,
1289 config_alias_order: None,
1290}];
1291
1292const ARCHITECTURE_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1293 feature: "diagram-architecture",
1294 id: "architecture",
1295 catalog_order: 4,
1296 detector: Some(ordered(4, crate::detect::detector_architecture)),
1297 semantic: Some(ordered(27, crate::diagrams::architecture::parse_architecture)),
1298 combined: Some(ordered(4, crate::diagrams::architecture::parse_architecture_json_and_editor_facts)),
1299 typed: Some(ordered(16, render_architecture)),
1300 render_kind: Some("architecture"),
1301 metadata: Some(metadata("architecture", Some(0))),
1302 headers: ARCHITECTURE_HEADERS,
1303 config_alias_order: None,
1304}];
1305
1306const ZENUML_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1307 feature: "diagram-zenuml",
1308 id: "zenuml",
1309 catalog_order: 5,
1310 detector: Some(ordered(5, crate::detect::detector_zenuml)),
1311 semantic: Some(ordered(15, crate::diagrams::zenuml::parse_zenuml)),
1312 combined: Some(ordered(36, crate::diagrams::zenuml::parse_zenuml_json_and_editor_facts)),
1313 typed: Some(ordered(3, render_zenuml)),
1314 render_kind: Some("zenuml"),
1315 metadata: Some(metadata("zenuml", Some(34))),
1316 headers: ZENUML_HEADERS,
1317 config_alias_order: None,
1318}];
1319
1320const SEQUENCE_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1321 feature: "diagram-sequence",
1322 id: "sequence",
1323 catalog_order: 15,
1324 detector: Some(ordered(15, crate::detect::detector_sequence)),
1325 semantic: Some(ordered(8, crate::diagrams::sequence::parse_sequence)),
1326 combined: Some(ordered(19, crate::diagrams::sequence::parse_sequence_json_and_editor_facts)),
1327 typed: Some(ordered(4, render_sequence)),
1328 render_kind: Some("sequence"),
1329 metadata: Some(metadata("sequence", Some(25))),
1330 headers: SEQUENCE_HEADERS,
1331 config_alias_order: None,
1332}];
1333
1334const C4_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1335 feature: "diagram-c4",
1336 id: "c4",
1337 catalog_order: 6,
1338 detector: Some(ordered(6, crate::detect::detector_c4)),
1339 semantic: Some(ordered(6, crate::diagrams::c4::parse_c4)),
1340 combined: Some(ordered(28, crate::diagrams::c4::parse_c4_json_and_editor_facts)),
1341 typed: Some(ordered(10, render_c4)),
1342 render_kind: Some("c4"),
1343 metadata: Some(metadata("c4", Some(2))),
1344 headers: C4_HEADERS,
1345 config_alias_order: None,
1346}];
1347
1348const KANBAN_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1349 feature: "diagram-kanban",
1350 id: "kanban",
1351 catalog_order: 7,
1352 detector: Some(ordered(7, crate::detect::detector_kanban)),
1353 semantic: Some(ordered(26, crate::diagrams::kanban::parse_kanban)),
1354 combined: Some(ordered(29, crate::diagrams::kanban::parse_kanban_json_and_editor_facts)),
1355 typed: Some(ordered(17, render_kanban)),
1356 render_kind: Some("kanban"),
1357 metadata: Some(metadata("kanban", Some(13))),
1358 headers: KANBAN_HEADERS,
1359 config_alias_order: None,
1360}];
1361
1362const CLASS_VARIANTS: &[FamilyVariantDefinition] = &[
1363 variant! {
1364 feature: "diagram-class",
1365 id: "classDiagram",
1366 catalog_order: 8,
1367 detector: Some(ordered(8, crate::detect::detector_class_v2)),
1368 semantic: Some(ordered(16, crate::diagrams::class::parse_class)),
1369 combined: Some(ordered(20, crate::diagrams::class::parse_class_json_and_editor_facts)),
1370 typed: Some(ordered(8, render_class)),
1371 render_kind: Some("class"),
1372 metadata: Some(metadata("class", Some(3))),
1373 headers: CLASS_HEADERS,
1374 config_alias_order: Some(0),
1375 },
1376 variant! {
1377 feature: "diagram-class",
1378 id: "class",
1379 catalog_order: 9,
1380 detector: None,
1381 semantic: Some(ordered(17, crate::diagrams::class::parse_class)),
1382 combined: Some(ordered(21, crate::diagrams::class::parse_class_json_and_editor_facts)),
1383 typed: Some(ordered(9, render_class)),
1384 render_kind: Some("class"),
1385 metadata: Some(metadata("class", None)),
1386 headers: &[],
1387 config_alias_order: None,
1388 },
1389];
1390
1391const ER_VARIANTS: &[FamilyVariantDefinition] = &[
1392 variant! {
1393 feature: "diagram-er",
1394 id: "er",
1395 catalog_order: 10,
1396 detector: Some(ordered(10, crate::detect::detector_er)),
1397 semantic: Some(ordered(18, crate::diagrams::er::parse_er)),
1398 combined: Some(ordered(17, crate::diagrams::er::parse_er_json_and_editor_facts)),
1399 typed: Some(ordered(29, render_er)),
1400 render_kind: Some("er"),
1401 metadata: Some(metadata("er", Some(5))),
1402 headers: ER_HEADERS,
1403 config_alias_order: None,
1404 },
1405 variant! {
1406 feature: "diagram-er",
1407 id: "erDiagram",
1408 catalog_order: 41,
1409 detector: None,
1410 semantic: Some(ordered(19, crate::diagrams::er::parse_er)),
1411 combined: Some(ordered(18, crate::diagrams::er::parse_er_json_and_editor_facts)),
1412 typed: Some(ordered(30, render_er)),
1413 render_kind: Some("er"),
1414 metadata: Some(metadata("er", None)),
1415 headers: &[],
1416 config_alias_order: Some(1),
1417 },
1418];
1419
1420const GANTT_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1421 feature: "diagram-gantt",
1422 id: "gantt",
1423 catalog_order: 11,
1424 detector: Some(ordered(11, crate::detect::detector_gantt)),
1425 semantic: Some(ordered(23, crate::diagrams::gantt::parse_gantt)),
1426 combined: Some(ordered(30, crate::diagrams::gantt::parse_gantt_json_and_editor_facts)),
1427 typed: Some(ordered(18, render_gantt)),
1428 render_kind: Some("gantt"),
1429 metadata: Some(metadata("gantt", Some(8))),
1430 headers: GANTT_HEADERS,
1431 config_alias_order: None,
1432}];
1433
1434const INFO_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1435 feature: "diagram-info",
1436 id: "info",
1437 catalog_order: 12,
1438 detector: Some(ordered(12, crate::detect::detector_info)),
1439 semantic: Some(ordered(4, crate::diagrams::info::parse_info)),
1440 combined: Some(ordered(10, crate::diagrams::info::parse_info_json_and_editor_facts)),
1441 typed: Some(ordered(26, render_info)),
1442 render_kind: Some("info"),
1443 metadata: Some(metadata("info", Some(10))),
1444 headers: INFO_HEADERS,
1445 config_alias_order: None,
1446}];
1447
1448const PIE_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1449 feature: "diagram-pie",
1450 id: "pie",
1451 catalog_order: 13,
1452 detector: Some(ordered(13, crate::detect::detector_pie)),
1453 semantic: Some(ordered(5, crate::diagrams::pie::parse_pie)),
1454 combined: Some(ordered(11, crate::diagrams::pie::parse_pie_json_and_editor_facts)),
1455 typed: Some(ordered(19, render_pie)),
1456 render_kind: Some("pie"),
1457 metadata: Some(metadata("pie", Some(16))),
1458 headers: PIE_HEADERS,
1459 config_alias_order: None,
1460}];
1461
1462const REQUIREMENT_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1463 feature: "diagram-requirement",
1464 id: "requirement",
1465 catalog_order: 14,
1466 detector: Some(ordered(14, crate::detect::detector_requirement)),
1467 semantic: Some(ordered(7, crate::diagrams::requirement::parse_requirement)),
1468 combined: Some(ordered(31, crate::diagrams::requirement::parse_requirement_json_and_editor_facts)),
1469 typed: Some(ordered(23, render_requirement)),
1470 render_kind: Some("requirement"),
1471 metadata: Some(metadata("requirement", Some(23))),
1472 headers: REQUIREMENT_HEADERS,
1473 config_alias_order: None,
1474}];
1475
1476const TIMELINE_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1477 feature: "diagram-timeline",
1478 id: "timeline",
1479 catalog_order: 19,
1480 detector: Some(ordered(19, crate::detect::detector_timeline)),
1481 semantic: Some(ordered(24, crate::diagrams::timeline::parse_timeline)),
1482 combined: Some(ordered(32, crate::diagrams::timeline::parse_timeline_json_and_editor_facts)),
1483 typed: Some(ordered(21, render_timeline)),
1484 render_kind: Some("timeline"),
1485 metadata: Some(metadata("timeline", Some(28))),
1486 headers: TIMELINE_HEADERS,
1487 config_alias_order: None,
1488}];
1489
1490const GIT_GRAPH_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1491 feature: "diagram-git-graph",
1492 id: "gitGraph",
1493 catalog_order: 20,
1494 detector: Some(ordered(20, crate::detect::detector_git_graph)),
1495 semantic: Some(ordered(29, crate::diagrams::git_graph::parse_git_graph)),
1496 warning_semantic: crate::diagrams::git_graph::parse_git_graph_with_warning_facts,
1497 combined: Some(ordered(15, crate::diagrams::git_graph::parse_git_graph_json_and_editor_facts)),
1498 typed: Some(ordered(33, render_git_graph)),
1499 render_kind: Some("gitGraph"),
1500 metadata: Some(metadata("gitgraph", Some(9))),
1501 headers: GIT_GRAPH_HEADERS,
1502 config_alias_order: None,
1503}];
1504
1505const STATE_VARIANTS: &[FamilyVariantDefinition] = &[
1506 variant! {
1507 feature: "diagram-state",
1508 id: "stateDiagram",
1509 catalog_order: 21,
1510 detector: Some(ordered(21, crate::detect::detector_state_v2)),
1511 semantic: Some(ordered(20, crate::diagrams::state::parse_state)),
1512 combined: Some(ordered(26, crate::diagrams::state::parse_state_json_and_editor_facts)),
1513 typed: Some(ordered(1, render_state)),
1514 render_kind: Some("state"),
1515 metadata: Some(metadata("state", Some(26))),
1516 headers: STATE_HEADERS,
1517 config_alias_order: Some(4),
1518 },
1519 variant! {
1520 feature: "diagram-state",
1521 id: "state",
1522 catalog_order: 22,
1523 detector: None,
1524 semantic: Some(ordered(21, crate::diagrams::state::parse_state)),
1525 combined: Some(ordered(27, crate::diagrams::state::parse_state_json_and_editor_facts)),
1526 typed: Some(ordered(2, render_state)),
1527 render_kind: Some("state"),
1528 metadata: Some(metadata("state", None)),
1529 headers: &[],
1530 config_alias_order: None,
1531 },
1532];
1533
1534const JOURNEY_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1535 feature: "diagram-journey",
1536 id: "journey",
1537 catalog_order: 23,
1538 detector: Some(ordered(23, crate::detect::detector_journey)),
1539 semantic: Some(ordered(25, crate::diagrams::journey::parse_journey)),
1540 combined: Some(ordered(33, crate::diagrams::journey::parse_journey_json_and_editor_facts)),
1541 typed: Some(ordered(22, render_journey)),
1542 render_kind: Some("journey"),
1543 metadata: Some(metadata("journey", Some(12))),
1544 headers: JOURNEY_HEADERS,
1545 config_alias_order: None,
1546}];
1547
1548const QUADRANT_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1549 feature: "diagram-quadrant-chart",
1550 id: "quadrantChart",
1551 catalog_order: 24,
1552 detector: Some(ordered(24, crate::detect::detector_quadrant)),
1553 semantic: Some(ordered(30, crate::diagrams::quadrant_chart::parse_quadrant_chart)),
1554 combined: Some(ordered(34, crate::diagrams::quadrant_chart::parse_quadrant_chart_json_and_editor_facts)),
1555 typed: Some(ordered(31, render_quadrant_chart)),
1556 render_kind: Some("quadrantChart"),
1557 metadata: Some(metadata("quadrantchart", Some(17))),
1558 headers: QUADRANT_HEADERS,
1559 config_alias_order: None,
1560}];
1561
1562const SANKEY_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1563 feature: "diagram-sankey",
1564 id: "sankey",
1565 catalog_order: 25,
1566 detector: Some(ordered(25, crate::detect::detector_sankey)),
1567 semantic: Some(ordered(38, crate::diagrams::sankey::parse_sankey)),
1568 combined: Some(ordered(16, crate::diagrams::sankey::parse_sankey_json_and_editor_facts)),
1569 typed: Some(ordered(24, render_sankey)),
1570 render_kind: Some("sankey"),
1571 metadata: Some(metadata("sankey", Some(24))),
1572 headers: SANKEY_HEADERS,
1573 config_alias_order: None,
1574}];
1575
1576const PACKET_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1577 feature: "diagram-packet",
1578 id: "packet",
1579 catalog_order: 26,
1580 detector: Some(ordered(26, crate::detect::detector_packet)),
1581 semantic: Some(ordered(31, crate::diagrams::packet::parse_packet)),
1582 combined: Some(ordered(12, crate::diagrams::packet::parse_packet_json_and_editor_facts)),
1583 typed: Some(ordered(20, render_packet)),
1584 render_kind: Some("packet"),
1585 metadata: Some(metadata("packet", Some(15))),
1586 headers: PACKET_HEADERS,
1587 config_alias_order: None,
1588}];
1589
1590const XYCHART_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1591 feature: "diagram-xychart",
1592 id: "xychart",
1593 catalog_order: 27,
1594 detector: Some(ordered(27, crate::detect::detector_xychart)),
1595 semantic: Some(ordered(39, crate::diagrams::xychart::parse_xychart)),
1596 combined: Some(ordered(38, crate::diagrams::xychart::parse_xychart_json_and_editor_facts)),
1597 typed: Some(ordered(32, render_xychart)),
1598 render_kind: Some("xychart"),
1599 metadata: Some(metadata("xychart", Some(33))),
1600 headers: XYCHART_HEADERS,
1601 config_alias_order: Some(5),
1602}];
1603
1604const BLOCK_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1605 feature: "diagram-block",
1606 id: "block",
1607 catalog_order: 28,
1608 detector: Some(ordered(28, crate::detect::detector_block)),
1609 semantic: Some(ordered(28, crate::diagrams::block::parse_block)),
1610 warning_semantic: crate::diagrams::block::parse_block_with_warning_facts,
1611 combined: Some(ordered(37, crate::diagrams::block::parse_block_json_and_editor_facts)),
1612 typed: Some(ordered(28, render_block)),
1613 render_kind: Some("block"),
1614 metadata: Some(metadata("block", Some(1))),
1615 headers: BLOCK_HEADERS,
1616 config_alias_order: None,
1617}];
1618
1619const EVENTMODELING_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1620 feature: "diagram-event-modeling",
1621 id: "eventmodeling",
1622 catalog_order: 29,
1623 detector: Some(ordered(29, crate::detect::detector_eventmodeling)),
1624 semantic: Some(ordered(35, crate::diagrams::eventmodeling::parse_eventmodeling)),
1625 combined: Some(ordered(22, crate::diagrams::eventmodeling::parse_eventmodeling_json_and_editor_facts)),
1626 typed: Some(ordered(36, render_eventmodeling)),
1627 render_kind: Some("eventmodeling"),
1628 metadata: Some(metadata("eventmodeling", Some(6))),
1629 headers: EVENTMODELING_HEADERS,
1630 config_alias_order: None,
1631}];
1632
1633const TREE_VIEW_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1634 feature: "diagram-tree-view",
1635 id: "treeView",
1636 catalog_order: 30,
1637 detector: Some(ordered(30, crate::detect::detector_tree_view)),
1638 semantic: Some(ordered(33, crate::diagrams::tree_view::parse_tree_view)),
1639 combined: Some(ordered(23, crate::diagrams::tree_view::parse_tree_view_json_and_editor_facts)),
1640 typed: Some(ordered(34, render_tree_view)),
1641 render_kind: Some("treeView"),
1642 metadata: Some(metadata("treeView", Some(29))),
1643 headers: TREE_VIEW_HEADERS,
1644 config_alias_order: None,
1645}];
1646
1647const RADAR_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1648 feature: "diagram-radar",
1649 id: "radar",
1650 catalog_order: 31,
1651 detector: Some(ordered(31, crate::detect::detector_radar)),
1652 semantic: Some(ordered(32, crate::diagrams::radar::parse_radar)),
1653 combined: Some(ordered(14, crate::diagrams::radar::parse_radar_json_and_editor_facts)),
1654 typed: Some(ordered(25, render_radar)),
1655 render_kind: Some("radar"),
1656 metadata: Some(metadata("radar", Some(18))),
1657 headers: RADAR_HEADERS,
1658 config_alias_order: None,
1659}];
1660
1661const ISHIKAWA_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1662 feature: "diagram-ishikawa",
1663 id: "ishikawa",
1664 catalog_order: 32,
1665 detector: Some(ordered(32, crate::detect::detector_ishikawa)),
1666 semantic: Some(ordered(34, crate::diagrams::ishikawa::parse_ishikawa)),
1667 combined: Some(ordered(24, crate::diagrams::ishikawa::parse_ishikawa_json_and_editor_facts)),
1668 typed: Some(ordered(35, render_ishikawa)),
1669 render_kind: Some("ishikawa"),
1670 metadata: Some(metadata("ishikawa", Some(11))),
1671 headers: ISHIKAWA_HEADERS,
1672 config_alias_order: None,
1673}];
1674
1675const TREEMAP_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1676 feature: "diagram-treemap",
1677 id: "treemap",
1678 catalog_order: 33,
1679 detector: Some(ordered(33, crate::detect::detector_treemap)),
1680 semantic: Some(ordered(36, crate::diagrams::treemap::parse_treemap)),
1681 combined: Some(ordered(25, crate::diagrams::treemap::parse_treemap_json_and_editor_facts)),
1682 typed: Some(ordered(27, render_treemap)),
1683 render_kind: Some("treemap"),
1684 metadata: Some(metadata("treemap", Some(30))),
1685 headers: TREEMAP_HEADERS,
1686 config_alias_order: None,
1687}];
1688
1689const RAILROAD_VARIANTS: &[FamilyVariantDefinition] = &[
1690 variant! {
1691 feature: "diagram-railroad",
1692 id: "railroad",
1693 catalog_order: 34,
1694 detector: Some(ordered(34, crate::detect::detector_railroad)),
1695 semantic: Some(ordered(11, crate::diagrams::railroad::parse_railroad)),
1696 combined: Some(ordered(6, crate::diagrams::railroad::parse_railroad_json_and_editor_facts)),
1697 typed: Some(ordered(12, render_railroad)),
1698 render_kind: Some("railroad"),
1699 metadata: Some(metadata("railroad", Some(19))),
1700 headers: RAILROAD_HEADERS,
1701 config_alias_order: None,
1702 },
1703 variant! {
1704 feature: "diagram-railroad",
1705 id: "railroadEbnf",
1706 catalog_order: 35,
1707 detector: Some(ordered(35, crate::detect::detector_railroad_ebnf)),
1708 semantic: Some(ordered(12, crate::diagrams::railroad::parse_railroad_ebnf)),
1709 combined: Some(ordered(7, crate::diagrams::railroad::parse_railroad_ebnf_json_and_editor_facts)),
1710 typed: Some(ordered(13, render_railroad_ebnf)),
1711 render_kind: Some("railroad"),
1712 metadata: Some(metadata("railroadEbnf", Some(21))),
1713 headers: RAILROAD_EBNF_HEADERS,
1714 config_alias_order: None,
1715 },
1716 variant! {
1717 feature: "diagram-railroad",
1718 id: "railroadAbnf",
1719 catalog_order: 36,
1720 detector: Some(ordered(36, crate::detect::detector_railroad_abnf)),
1721 semantic: Some(ordered(13, crate::diagrams::railroad::parse_railroad_abnf)),
1722 combined: Some(ordered(8, crate::diagrams::railroad::parse_railroad_abnf_json_and_editor_facts)),
1723 typed: Some(ordered(14, render_railroad_abnf)),
1724 render_kind: Some("railroad"),
1725 metadata: Some(metadata("railroadAbnf", Some(20))),
1726 headers: RAILROAD_ABNF_HEADERS,
1727 config_alias_order: None,
1728 },
1729 variant! {
1730 feature: "diagram-railroad",
1731 id: "railroadPeg",
1732 catalog_order: 37,
1733 detector: Some(ordered(37, crate::detect::detector_railroad_peg)),
1734 semantic: Some(ordered(14, crate::diagrams::railroad::parse_railroad_peg)),
1735 combined: Some(ordered(9, crate::diagrams::railroad::parse_railroad_peg_json_and_editor_facts)),
1736 typed: Some(ordered(15, render_railroad_peg)),
1737 render_kind: Some("railroad"),
1738 metadata: Some(metadata("railroadPeg", Some(22))),
1739 headers: RAILROAD_PEG_HEADERS,
1740 config_alias_order: None,
1741 },
1742];
1743
1744const VENN_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1745 feature: "diagram-venn",
1746 id: "venn",
1747 catalog_order: 38,
1748 detector: Some(ordered(38, crate::detect::detector_venn)),
1749 semantic: Some(ordered(37, crate::diagrams::venn::parse_venn)),
1750 combined: Some(ordered(35, crate::diagrams::venn::parse_venn_json_and_editor_facts)),
1751 typed: Some(ordered(37, render_venn)),
1752 render_kind: Some("venn"),
1753 metadata: Some(metadata("venn", Some(31))),
1754 headers: VENN_HEADERS,
1755 config_alias_order: None,
1756}];
1757
1758const WARDLEY_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1759 feature: "diagram-wardley",
1760 id: "wardley",
1761 catalog_order: 39,
1762 detector: Some(ordered(39, crate::detect::detector_wardley)),
1763 semantic: Some(ordered(40, crate::diagrams::wardley::parse_wardley)),
1764 combined: Some(ordered(39, crate::diagrams::wardley::parse_wardley_json_and_editor_facts)),
1765 typed: Some(ordered(40, render_wardley)),
1766 render_kind: Some("wardley"),
1767 metadata: Some(metadata("wardley", Some(32))),
1768 headers: WARDLEY_HEADERS,
1769 config_alias_order: None,
1770}];
1771
1772const CYNEFIN_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1773 feature: "diagram-cynefin",
1774 id: "cynefin",
1775 catalog_order: 40,
1776 detector: Some(ordered(40, crate::detect::detector_cynefin)),
1777 semantic: Some(ordered(10, crate::diagrams::cynefin::parse_cynefin)),
1778 combined: Some(ordered(13, crate::diagrams::cynefin::parse_cynefin_json_and_editor_facts)),
1779 typed: Some(ordered(11, render_cynefin)),
1780 render_kind: Some("cynefin"),
1781 metadata: Some(metadata("cynefin", Some(4))),
1782 headers: CYNEFIN_HEADERS,
1783 config_alias_order: None,
1784}];
1785
1786const USECASE_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1787 feature: "diagram-usecase",
1788 id: "usecase",
1789 catalog_order: 42,
1790 detector: Some(ordered(42, crate::detect::detector_usecase)),
1791 semantic: Some(ordered(42, crate::diagrams::usecase::parse_usecase)),
1792 combined: Some(ordered(42, crate::diagrams::usecase::parse_usecase_json_and_editor_facts)),
1793 typed: Some(ordered(42, render_usecase)),
1794 render_kind: Some("usecase"),
1795 metadata: Some(metadata("usecase", Some(36))),
1796 headers: USECASE_HEADERS,
1797 config_alias_order: None,
1798}];
1799
1800const AGENTFLOW_VARIANTS: &[FamilyVariantDefinition] = &[variant! {
1801 feature: "diagram-agentflow",
1802 id: "agentflow",
1803 catalog_order: 43,
1804 detector: Some(ordered(43, crate::detect::detector_agentflow)),
1805 semantic: Some(ordered(43, crate::diagrams::agentflow::parse_agentflow)),
1806 warning_semantic: crate::diagrams::agentflow::parse_agentflow_with_warning_facts,
1807 combined: Some(ordered(43, crate::diagrams::agentflow::parse_agentflow_json_and_editor_facts)),
1808 typed: Some(ordered(43, render_agentflow)),
1809 render_kind: Some("agentflow"),
1810 metadata: Some(metadata("agentflow", Some(35))),
1811 headers: AGENTFLOW_HEADERS,
1812 config_alias_order: Some(36),
1813}];
1814
1815const FAMILY_CATALOG: &[DiagramFamilyDefinition] = &[
1816 DiagramFamilyDefinition {
1817 logical_kind: "error",
1818 selector: None,
1819 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1820 config: None,
1821 variants: ERROR_VARIANTS,
1822 },
1823 DiagramFamilyDefinition {
1824 logical_kind: "flowchart",
1825 selector: Some("diagram-flowchart"),
1826 editor_semantics: FLOWCHART_EDITOR_SEMANTICS,
1827 config: Some(FamilyConfigDefinition {
1828 namespace: "flowchart",
1829 frontmatter_order: 7,
1830 }),
1831 variants: FLOWCHART_VARIANTS,
1832 },
1833 DiagramFamilyDefinition {
1834 logical_kind: "swimlane",
1835 selector: Some("diagram-swimlane"),
1836 editor_semantics: SWIMLANE_EDITOR_SEMANTICS,
1837 config: Some(FamilyConfigDefinition {
1838 namespace: "swimlane",
1839 frontmatter_order: 23,
1840 }),
1841 variants: SWIMLANE_VARIANTS,
1842 },
1843 DiagramFamilyDefinition {
1844 logical_kind: "mindmap",
1845 selector: Some("diagram-mindmap"),
1846 editor_semantics: MINDMAP_EDITOR_SEMANTICS,
1847 config: Some(FamilyConfigDefinition {
1848 namespace: "mindmap",
1849 frontmatter_order: 13,
1850 }),
1851 variants: MINDMAP_VARIANTS,
1852 },
1853 DiagramFamilyDefinition {
1854 logical_kind: "architecture",
1855 selector: Some("diagram-architecture"),
1856 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1857 config: Some(FamilyConfigDefinition {
1858 namespace: "architecture",
1859 frontmatter_order: 0,
1860 }),
1861 variants: ARCHITECTURE_VARIANTS,
1862 },
1863 DiagramFamilyDefinition {
1864 logical_kind: "zenuml",
1865 selector: Some("diagram-zenuml"),
1866 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1867 config: Some(FamilyConfigDefinition {
1868 namespace: "zenuml",
1869 frontmatter_order: 30,
1870 }),
1871 variants: ZENUML_VARIANTS,
1872 },
1873 DiagramFamilyDefinition {
1874 logical_kind: "sequence",
1875 selector: Some("diagram-sequence"),
1876 editor_semantics: SEQUENCE_EDITOR_SEMANTICS,
1877 config: Some(FamilyConfigDefinition {
1878 namespace: "sequence",
1879 frontmatter_order: 21,
1880 }),
1881 variants: SEQUENCE_VARIANTS,
1882 },
1883 DiagramFamilyDefinition {
1884 logical_kind: "c4",
1885 selector: Some("diagram-c4"),
1886 editor_semantics: CARDINAL_EDITOR_SEMANTICS,
1887 config: Some(FamilyConfigDefinition {
1888 namespace: "c4",
1889 frontmatter_order: 2,
1890 }),
1891 variants: C4_VARIANTS,
1892 },
1893 DiagramFamilyDefinition {
1894 logical_kind: "kanban",
1895 selector: Some("diagram-kanban"),
1896 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1897 config: Some(FamilyConfigDefinition {
1898 namespace: "kanban",
1899 frontmatter_order: 12,
1900 }),
1901 variants: KANBAN_VARIANTS,
1902 },
1903 DiagramFamilyDefinition {
1904 logical_kind: "class",
1905 selector: Some("diagram-class"),
1906 editor_semantics: CLASS_EDITOR_SEMANTICS,
1907 config: Some(FamilyConfigDefinition {
1908 namespace: "class",
1909 frontmatter_order: 3,
1910 }),
1911 variants: CLASS_VARIANTS,
1912 },
1913 DiagramFamilyDefinition {
1914 logical_kind: "er",
1915 selector: Some("diagram-er"),
1916 editor_semantics: ER_EDITOR_SEMANTICS,
1917 config: Some(FamilyConfigDefinition {
1918 namespace: "er",
1919 frontmatter_order: 5,
1920 }),
1921 variants: ER_VARIANTS,
1922 },
1923 DiagramFamilyDefinition {
1924 logical_kind: "gantt",
1925 selector: Some("diagram-gantt"),
1926 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1927 config: Some(FamilyConfigDefinition {
1928 namespace: "gantt",
1929 frontmatter_order: 8,
1930 }),
1931 variants: GANTT_VARIANTS,
1932 },
1933 DiagramFamilyDefinition {
1934 logical_kind: "info",
1935 selector: Some("diagram-info"),
1936 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1937 config: None,
1938 variants: INFO_VARIANTS,
1939 },
1940 DiagramFamilyDefinition {
1941 logical_kind: "pie",
1942 selector: Some("diagram-pie"),
1943 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1944 config: Some(FamilyConfigDefinition {
1945 namespace: "pie",
1946 frontmatter_order: 15,
1947 }),
1948 variants: PIE_VARIANTS,
1949 },
1950 DiagramFamilyDefinition {
1951 logical_kind: "requirement",
1952 selector: Some("diagram-requirement"),
1953 editor_semantics: CARDINAL_EDITOR_SEMANTICS,
1954 config: Some(FamilyConfigDefinition {
1955 namespace: "requirement",
1956 frontmatter_order: 19,
1957 }),
1958 variants: REQUIREMENT_VARIANTS,
1959 },
1960 DiagramFamilyDefinition {
1961 logical_kind: "timeline",
1962 selector: Some("diagram-timeline"),
1963 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1964 config: Some(FamilyConfigDefinition {
1965 namespace: "timeline",
1966 frontmatter_order: 24,
1967 }),
1968 variants: TIMELINE_VARIANTS,
1969 },
1970 DiagramFamilyDefinition {
1971 logical_kind: "gitGraph",
1972 selector: Some("diagram-git-graph"),
1973 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1974 config: Some(FamilyConfigDefinition {
1975 namespace: "gitGraph",
1976 frontmatter_order: 9,
1977 }),
1978 variants: GIT_GRAPH_VARIANTS,
1979 },
1980 DiagramFamilyDefinition {
1981 logical_kind: "state",
1982 selector: Some("diagram-state"),
1983 editor_semantics: STATE_EDITOR_SEMANTICS,
1984 config: Some(FamilyConfigDefinition {
1985 namespace: "state",
1986 frontmatter_order: 22,
1987 }),
1988 variants: STATE_VARIANTS,
1989 },
1990 DiagramFamilyDefinition {
1991 logical_kind: "journey",
1992 selector: Some("diagram-journey"),
1993 editor_semantics: GENERIC_EDITOR_SEMANTICS,
1994 config: Some(FamilyConfigDefinition {
1995 namespace: "journey",
1996 frontmatter_order: 11,
1997 }),
1998 variants: JOURNEY_VARIANTS,
1999 },
2000 DiagramFamilyDefinition {
2001 logical_kind: "quadrantChart",
2002 selector: Some("diagram-quadrant-chart"),
2003 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2004 config: Some(FamilyConfigDefinition {
2005 namespace: "quadrantChart",
2006 frontmatter_order: 16,
2007 }),
2008 variants: QUADRANT_VARIANTS,
2009 },
2010 DiagramFamilyDefinition {
2011 logical_kind: "sankey",
2012 selector: Some("diagram-sankey"),
2013 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2014 config: Some(FamilyConfigDefinition {
2015 namespace: "sankey",
2016 frontmatter_order: 20,
2017 }),
2018 variants: SANKEY_VARIANTS,
2019 },
2020 DiagramFamilyDefinition {
2021 logical_kind: "packet",
2022 selector: Some("diagram-packet"),
2023 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2024 config: Some(FamilyConfigDefinition {
2025 namespace: "packet",
2026 frontmatter_order: 14,
2027 }),
2028 variants: PACKET_VARIANTS,
2029 },
2030 DiagramFamilyDefinition {
2031 logical_kind: "xychart",
2032 selector: Some("diagram-xychart"),
2033 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2034 config: Some(FamilyConfigDefinition {
2035 namespace: "xyChart",
2036 frontmatter_order: 29,
2037 }),
2038 variants: XYCHART_VARIANTS,
2039 },
2040 DiagramFamilyDefinition {
2041 logical_kind: "block",
2042 selector: Some("diagram-block"),
2043 editor_semantics: BLOCK_EDITOR_SEMANTICS,
2044 config: Some(FamilyConfigDefinition {
2045 namespace: "block",
2046 frontmatter_order: 1,
2047 }),
2048 variants: BLOCK_VARIANTS,
2049 },
2050 DiagramFamilyDefinition {
2051 logical_kind: "eventmodeling",
2052 selector: Some("diagram-event-modeling"),
2053 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2054 config: Some(FamilyConfigDefinition {
2055 namespace: "eventmodeling",
2056 frontmatter_order: 6,
2057 }),
2058 variants: EVENTMODELING_VARIANTS,
2059 },
2060 DiagramFamilyDefinition {
2061 logical_kind: "treeView",
2062 selector: Some("diagram-tree-view"),
2063 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2064 config: Some(FamilyConfigDefinition {
2065 namespace: "treeView",
2066 frontmatter_order: 25,
2067 }),
2068 variants: TREE_VIEW_VARIANTS,
2069 },
2070 DiagramFamilyDefinition {
2071 logical_kind: "radar",
2072 selector: Some("diagram-radar"),
2073 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2074 config: Some(FamilyConfigDefinition {
2075 namespace: "radar",
2076 frontmatter_order: 17,
2077 }),
2078 variants: RADAR_VARIANTS,
2079 },
2080 DiagramFamilyDefinition {
2081 logical_kind: "ishikawa",
2082 selector: Some("diagram-ishikawa"),
2083 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2084 config: Some(FamilyConfigDefinition {
2085 namespace: "ishikawa",
2086 frontmatter_order: 10,
2087 }),
2088 variants: ISHIKAWA_VARIANTS,
2089 },
2090 DiagramFamilyDefinition {
2091 logical_kind: "treemap",
2092 selector: Some("diagram-treemap"),
2093 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2094 config: Some(FamilyConfigDefinition {
2095 namespace: "treemap",
2096 frontmatter_order: 26,
2097 }),
2098 variants: TREEMAP_VARIANTS,
2099 },
2100 DiagramFamilyDefinition {
2101 logical_kind: "railroad",
2102 selector: Some("diagram-railroad"),
2103 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2104 config: Some(FamilyConfigDefinition {
2105 namespace: "railroad",
2106 frontmatter_order: 18,
2107 }),
2108 variants: RAILROAD_VARIANTS,
2109 },
2110 DiagramFamilyDefinition {
2111 logical_kind: "venn",
2112 selector: Some("diagram-venn"),
2113 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2114 config: Some(FamilyConfigDefinition {
2115 namespace: "venn",
2116 frontmatter_order: 27,
2117 }),
2118 variants: VENN_VARIANTS,
2119 },
2120 DiagramFamilyDefinition {
2121 logical_kind: "wardley",
2122 selector: Some("diagram-wardley"),
2123 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2124 config: Some(FamilyConfigDefinition {
2125 namespace: "wardley-beta",
2126 frontmatter_order: 28,
2127 }),
2128 variants: WARDLEY_VARIANTS,
2129 },
2130 DiagramFamilyDefinition {
2131 logical_kind: "cynefin",
2132 selector: Some("diagram-cynefin"),
2133 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2134 config: Some(FamilyConfigDefinition {
2135 namespace: "cynefin",
2136 frontmatter_order: 4,
2137 }),
2138 variants: CYNEFIN_VARIANTS,
2139 },
2140 DiagramFamilyDefinition {
2141 logical_kind: "usecase",
2142 selector: Some("diagram-usecase"),
2143 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2144 config: Some(FamilyConfigDefinition {
2145 namespace: "usecase",
2146 frontmatter_order: 35,
2147 }),
2148 variants: USECASE_VARIANTS,
2149 },
2150 DiagramFamilyDefinition {
2151 logical_kind: "agentflow",
2152 selector: Some("diagram-agentflow"),
2153 editor_semantics: GENERIC_EDITOR_SEMANTICS,
2154 config: Some(FamilyConfigDefinition {
2155 namespace: "agentflow",
2156 frontmatter_order: 36,
2157 }),
2158 variants: AGENTFLOW_VARIANTS,
2159 },
2160];
2161
2162#[cfg(test)]
2163mod catalog_tests {
2164 use super::*;
2165 use std::collections::BTreeSet;
2166
2167 #[test]
2168 fn selectors_cover_logical_families_once_without_infrastructure_or_aliases() {
2169 let selectors = diagram_family_selectors();
2170 assert_eq!(selectors.len(), 34);
2171 let mut features = BTreeSet::new();
2172 let mut families = BTreeSet::new();
2173 for selector in selectors {
2174 assert!(features.insert(selector.feature));
2175 assert!(families.insert(selector.logical_family_kind));
2176 assert!(selector.feature.starts_with("diagram-"));
2177 assert!(
2178 selector
2179 .feature
2180 .bytes()
2181 .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-')
2182 );
2183 }
2184 for family in FAMILY_CATALOG {
2185 assert_eq!(family.selector.is_some(), family.logical_kind != "error");
2186 assert_eq!(
2187 families.contains(family.logical_kind),
2188 family.logical_kind != "error"
2189 );
2190 }
2191 for (id, expected) in [
2192 ("flowchart", "diagram-flowchart"),
2193 ("flowchart-v2", "diagram-flowchart"),
2194 ("flowchart-elk", "diagram-flowchart"),
2195 ("swimlane", "diagram-swimlane"),
2196 ("gitGraph", "diagram-git-graph"),
2197 ("quadrantChart", "diagram-quadrant-chart"),
2198 ("treeView", "diagram-tree-view"),
2199 ("eventmodeling", "diagram-event-modeling"),
2200 ] {
2201 let (family, _) = find_variant(id).expect("known family alias");
2202 assert_eq!(family.selector, Some(expected), "{id}");
2203 }
2204 assert!(!features.contains("diagram-error"));
2205 assert!(!features.contains("diagram-flowchart-elk"));
2206 }
2207
2208 #[test]
2209 fn public_metadata_ids_are_catalog_owned_instead_of_derived_from_family_names() {
2210 assert_eq!(diagram_type_metadata_id("flowchart-v2"), Some("flowchart"));
2211 assert_eq!(diagram_type_metadata_id("gitGraph"), Some("gitgraph"));
2212 assert_eq!(
2213 diagram_type_metadata_id("quadrantChart"),
2214 Some("quadrantchart")
2215 );
2216 assert_eq!(diagram_type_metadata_id("treeView"), Some("treeView"));
2217 }
2218
2219 #[test]
2220 fn editor_semantics_follow_family_identity_across_variant_ids() {
2221 for variant in ["flowchart-v2", "flowchart-elk", "flowchart"] {
2222 assert_eq!(
2223 diagram_type_family_id(variant),
2224 Some(DiagramFamilyId::FLOWCHART),
2225 "{variant} must retain typed Flowchart family identity"
2226 );
2227 }
2228
2229 let flowchart = diagram_type_editor_semantics("flowchart-v2")
2230 .expect("flowchart-v2 has editor family semantics");
2231 for variant in ["flowchart-elk", "flowchart"] {
2232 assert_eq!(
2233 diagram_type_editor_semantics(variant),
2234 Some(flowchart),
2235 "{variant} must inherit flowchart family semantics"
2236 );
2237 }
2238
2239 let class = diagram_type_editor_semantics("classDiagram")
2240 .expect("classDiagram has editor family semantics");
2241 assert_eq!(diagram_type_editor_semantics("class"), Some(class));
2242 assert_ne!(flowchart, class);
2243 }
2244
2245 #[test]
2246 fn absent_implementations_preserve_the_complete_identity_projection() {
2247 let unavailable = variants()
2248 .map(|(family, variant)| {
2249 (
2250 family,
2251 FamilyVariantDefinition {
2252 identity: variant.identity,
2253 implementation: FamilyImplementation::default(),
2254 },
2255 )
2256 })
2257 .collect::<Vec<_>>();
2258 let projected = FamilyCatalogProjection::build(
2259 unavailable
2260 .iter()
2261 .map(|(family, variant)| (*family, variant)),
2262 );
2263 let complete = family_catalog_projection();
2264
2265 assert!(projected.semantic_parser_facts.is_empty());
2266 assert!(projected.combined_parser_facts.is_empty());
2267 assert!(projected.render_parser_facts.is_empty());
2268 assert!(projected.supported_diagram_metadata_ids.is_empty());
2269 assert!(projected.built_in_typed_render_families.is_empty());
2270 assert_eq!(
2271 projected.diagram_header_facts,
2272 complete.diagram_header_facts
2273 );
2274 assert_eq!(
2275 projected
2276 .detector_facts
2277 .iter()
2278 .map(|fact| fact.id)
2279 .collect::<Vec<_>>(),
2280 complete
2281 .detector_facts
2282 .iter()
2283 .map(|fact| fact.id)
2284 .collect::<Vec<_>>()
2285 );
2286 let expected = complete
2287 .diagram_family_capabilities
2288 .iter()
2289 .map(|fact| DiagramFamilyCapability {
2290 has_semantic_parser: false,
2291 has_editor_parser: false,
2292 has_combined_parser: false,
2293 has_render_parser: false,
2294 ..*fact
2295 })
2296 .collect::<Vec<_>>();
2297 assert_eq!(projected.diagram_family_capabilities, expected);
2298 }
2299
2300 #[test]
2301 #[cfg(feature = "diagram-flowchart")]
2302 fn parser_and_typed_model_enumerations_follow_their_own_callbacks() {
2303 let (family, variant) = find_variant("flowchart-v2").unwrap();
2304 let semantic_only = FamilyVariantDefinition {
2305 identity: variant.identity,
2306 implementation: FamilyImplementation {
2307 semantic: variant.implementation.semantic,
2308 ..FamilyImplementation::default()
2309 },
2310 };
2311 let projected = FamilyCatalogProjection::build([(family, &semantic_only)]);
2312 assert_eq!(projected.supported_diagram_metadata_ids, ["flowchart"]);
2313 assert!(projected.built_in_typed_render_families.is_empty());
2314 assert!(projected.diagram_family_capabilities[0].has_semantic_parser);
2315 assert!(!projected.diagram_family_capabilities[0].has_editor_parser);
2316 assert!(!projected.diagram_family_capabilities[0].has_render_parser);
2317
2318 let typed_only = FamilyVariantDefinition {
2319 identity: variant.identity,
2320 implementation: FamilyImplementation {
2321 typed_render: variant.implementation.typed_render,
2322 ..FamilyImplementation::default()
2323 },
2324 };
2325 let projected = FamilyCatalogProjection::build([(family, &typed_only)]);
2326 assert!(projected.supported_diagram_metadata_ids.is_empty());
2327 assert_eq!(
2328 projected.built_in_typed_render_families,
2329 [BuiltInTypedRenderFamily {
2330 diagram_type: "flowchart",
2331 render_model_kind: "flowchart",
2332 }]
2333 );
2334 assert!(!projected.diagram_family_capabilities[0].has_semantic_parser);
2335 assert!(projected.diagram_family_capabilities[0].has_render_parser);
2336 }
2337
2338 #[test]
2339 #[cfg(feature = "diagram-swimlane")]
2340 fn shared_typed_models_do_not_admit_an_unavailable_logical_family() {
2341 let projected_variants = variants()
2342 .map(|(family, variant)| {
2343 let mut variant = *variant;
2344 if family.logical_kind != "swimlane" {
2345 variant.implementation = FamilyImplementation::default();
2346 }
2347 (family, variant)
2348 })
2349 .collect::<Vec<_>>();
2350 let projected = FamilyCatalogProjection::build(
2351 projected_variants
2352 .iter()
2353 .map(|(family, variant)| (*family, variant)),
2354 );
2355 assert_eq!(projected.supported_diagram_metadata_ids, ["swimlane"]);
2356 assert_eq!(
2357 projected.built_in_typed_render_families,
2358 [BuiltInTypedRenderFamily {
2359 diagram_type: "swimlane",
2360 render_model_kind: "flowchart",
2361 }]
2362 );
2363 assert!(
2364 projected.diagram_family_capabilities.iter().all(|fact| {
2365 fact.has_semantic_parser == (fact.logical_family_kind == "swimlane")
2366 })
2367 );
2368 }
2369
2370 #[test]
2371 fn catalog_ids_orders_and_family_policy_are_internally_consistent() {
2372 let mut ids = BTreeSet::new();
2373 let mut catalog_orders = BTreeSet::new();
2374 let mut detector_orders = BTreeSet::new();
2375 let mut semantic_orders = BTreeSet::new();
2376 let mut combined_orders = BTreeSet::new();
2377 let mut render_orders = BTreeSet::new();
2378 let mut metadata_orders = BTreeSet::new();
2379 let mut header_orders = BTreeSet::new();
2380
2381 for family in FAMILY_CATALOG {
2382 for variant in family.variants {
2383 assert_ne!(
2384 variant.identity.id, "---",
2385 "frontmatter guard is not a family"
2386 );
2387 assert!(
2388 ids.insert(variant.identity.id),
2389 "duplicate catalog id {}",
2390 variant.identity.id
2391 );
2392 assert!(
2393 catalog_orders.insert(variant.identity.catalog_order),
2394 "duplicate catalog order {}",
2395 variant.identity.catalog_order
2396 );
2397 assert!(
2398 variant.implementation.typed_render.is_none()
2399 || variant.identity.render_model_kind.is_some(),
2400 "{} typed parser requires a known render kind",
2401 variant.identity.id
2402 );
2403 assert!(
2404 variant.identity.metadata.is_none()
2405 || variant.identity.render_model_kind.is_some(),
2406 "{} metadata requires a known render kind",
2407 variant.identity.id
2408 );
2409 assert!(
2410 variant.implementation.combined.is_none()
2411 || variant.implementation.semantic.is_some(),
2412 "{} combined parsing requires a semantic adapter",
2413 variant.identity.id
2414 );
2415
2416 if let Some(fact) = variant.identity.detector {
2417 assert!(detector_orders.insert(fact.order));
2418 }
2419 if let Some(fact) = variant.implementation.semantic {
2420 assert!(semantic_orders.insert(fact.order));
2421 }
2422 if let Some(fact) = variant.implementation.combined {
2423 assert!(combined_orders.insert(fact.order));
2424 }
2425 if let Some(fact) = variant.implementation.typed_render {
2426 assert!(render_orders.insert(fact.order));
2427 }
2428 if let Some(order) = variant
2429 .identity
2430 .metadata
2431 .and_then(|metadata| metadata.order)
2432 {
2433 assert!(metadata_orders.insert(order));
2434 }
2435 for fact in variant.identity.headers {
2436 assert!(header_orders.insert(fact.order));
2437 }
2438 }
2439 }
2440
2441 let config_orders = FAMILY_CATALOG
2442 .iter()
2443 .filter_map(|family| family.config.map(|config| config.frontmatter_order))
2444 .collect::<BTreeSet<_>>();
2445 let config_count = FAMILY_CATALOG
2446 .iter()
2447 .filter(|family| family.config.is_some())
2448 .count();
2449 assert_eq!(config_orders.len(), config_count);
2450 assert_eq!(ids.len(), diagram_family_capabilities().len());
2451 }
2452}