1use std::fmt;
2use std::path::{Component, Path};
3
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
13#[serde(transparent)]
14pub struct SemanticId(String);
15
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
22#[serde(transparent)]
23pub struct EffectId(SemanticId);
24
25#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
30#[serde(transparent)]
31pub struct EffectStatementId(SemanticId);
32
33#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
38#[serde(transparent)]
39pub struct ContextId(SemanticId);
40
41#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
43#[serde(transparent)]
44pub struct ProviderId(SemanticId);
45
46#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
48#[serde(transparent)]
49pub struct ConsumerId(SemanticId);
50
51#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
53#[serde(transparent)]
54pub struct FormId(SemanticId);
55
56#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
61#[serde(transparent)]
62pub struct FormInstanceId(SemanticId);
63
64#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
69#[serde(transparent)]
70pub struct FormDeclarationCandidateId(SemanticId);
71
72#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
75#[serde(transparent)]
76pub struct FormFieldDeclarationCandidateId(SemanticId);
77
78#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
81#[serde(transparent)]
82pub struct FormFieldBindingCandidateId(SemanticId);
83
84#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
86#[serde(transparent)]
87pub struct FieldId(SemanticId);
88
89#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
92#[serde(transparent)]
93pub struct FieldBindingId(SemanticId);
94
95#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
98#[serde(transparent)]
99pub struct SubmissionHostCandidateId(SemanticId);
100
101#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
103#[serde(transparent)]
104pub struct SubmissionHostId(SemanticId);
105
106#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
109#[serde(transparent)]
110pub struct FormOwnershipGraphId(SemanticId);
111
112#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
114#[serde(transparent)]
115pub struct ValidationRuleCandidateId(SemanticId);
116
117#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
119#[serde(transparent)]
120pub struct ValidationRuleId(SemanticId);
121
122#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
124#[serde(transparent)]
125pub struct ValidationGraphId(SemanticId);
126
127#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
131#[serde(transparent)]
132pub struct ValidationPlanId(SemanticId);
133
134#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
136#[serde(transparent)]
137pub struct FieldDependencyId(SemanticId);
138
139#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
141#[serde(transparent)]
142pub struct ValidationDependencyCycleId(SemanticId);
143
144#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
146#[serde(transparent)]
147pub struct DirtyTrackingPlanId(SemanticId);
148
149#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
151#[serde(transparent)]
152pub struct TouchedTrackingPlanId(SemanticId);
153
154#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
157#[serde(transparent)]
158pub struct FieldTrackingId(SemanticId);
159
160#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
162#[serde(transparent)]
163pub struct SubmissionDeclarationCandidateId(SemanticId);
164
165#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
167#[serde(transparent)]
168pub struct SubmissionPlanId(SemanticId);
169
170#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
172#[serde(transparent)]
173pub struct SerializationPlanId(SemanticId);
174
175#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
176#[serde(transparent)]
177pub struct ResetPlanId(SemanticId);
178
179#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
180#[serde(transparent)]
181pub struct FieldResetOperationId(SemanticId);
182
183#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
184#[serde(transparent)]
185pub struct FormFieldValueSlotId(SemanticId);
186#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
187#[serde(transparent)]
188pub struct FormFieldDirtySlotId(SemanticId);
189#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
190#[serde(transparent)]
191pub struct FormFieldTouchedSlotId(SemanticId);
192#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
193#[serde(transparent)]
194pub struct FormFieldValidationSlotId(SemanticId);
195#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
196#[serde(transparent)]
197pub struct FormValidationAggregateSlotId(SemanticId);
198#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
199#[serde(transparent)]
200pub struct FormSubmissionStateSlotId(SemanticId);
201
202#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
204#[serde(transparent)]
205pub struct SlotId(SemanticId);
206
207#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
212#[serde(transparent)]
213pub struct SlotDeclarationCandidateId(SemanticId);
214
215#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
217#[serde(transparent)]
218pub struct ComponentInvocationId(SemanticId);
219
220#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
222#[serde(transparent)]
223pub struct TemplatePositionId(SemanticId);
224
225#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
227#[serde(transparent)]
228pub struct SlotContentFragmentId(SemanticId);
229
230#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
232#[serde(transparent)]
233pub struct SlotOutletId(SemanticId);
234
235#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
237#[serde(transparent)]
238pub struct SlotBindingId(SemanticId);
239
240#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
242#[serde(transparent)]
243pub struct ComponentRootId(SemanticId);
244
245#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
247#[serde(transparent)]
248pub struct ComponentInstanceId(SemanticId);
249
250#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
252#[serde(transparent)]
253pub struct ComponentStructuralRegionId(SemanticId);
254
255#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
260#[serde(transparent)]
261pub struct ResourceId(SemanticId);
262
263#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
265#[serde(transparent)]
266pub struct ResourceActivationId(SemanticId);
267
268#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
270#[serde(transparent)]
271pub struct EffectInstanceId(SemanticId);
272
273#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
278#[serde(transparent)]
279pub struct ContextDeclarationCandidateId(SemanticId);
280
281#[derive(Debug, Clone, PartialEq, Eq)]
283pub enum SemanticOwner {
284 Application,
285 Entity(SemanticId),
286}
287
288impl SemanticOwner {
289 #[must_use]
290 pub fn entity(id: SemanticId) -> Self {
291 Self::Entity(id)
292 }
293
294 #[must_use]
295 pub fn entity_id(&self) -> Option<&SemanticId> {
296 match self {
297 Self::Application => None,
298 Self::Entity(id) => Some(id),
299 }
300 }
301}
302
303impl SemanticId {
304 #[must_use]
305 pub fn component_root(component: &Self) -> Self {
306 Self(format!("root:{}", component.as_str()))
307 }
308 #[must_use]
309 pub fn component(element_name: Option<&str>, class_name: &str) -> Self {
310 Self(format!("component:{}", element_name.unwrap_or(class_name)))
311 }
312
313 #[must_use]
314 pub fn component_in_module(
315 module_path: impl AsRef<Path>,
316 element_name: Option<&str>,
317 class_name: &str,
318 ) -> Self {
319 Self(format!(
320 "module:{}/component:{}",
321 normalized_module_path(module_path.as_ref()),
322 element_name.unwrap_or(class_name)
323 ))
324 }
325
326 #[must_use]
327 pub fn type_alias_in_module(module_path: impl AsRef<Path>, name: &str) -> Self {
328 Self(format!(
329 "module:{}/type-alias:{name}",
330 normalized_module_path(module_path.as_ref())
331 ))
332 }
333
334 #[must_use]
337 pub fn environment_read_in_module(module_path: impl AsRef<Path>, position: usize) -> Self {
338 Self(format!(
339 "module:{}/environment-read:{position}",
340 normalized_module_path(module_path.as_ref())
341 ))
342 }
343
344 #[must_use]
345 pub fn state_field(&self, name: &str) -> Self {
346 self.child("state", name)
347 }
348
349 #[must_use]
350 pub fn method(&self, name: &str) -> Self {
351 self.child("method", name)
352 }
353
354 #[must_use]
355 pub fn computed(&self, name: &str) -> Self {
356 self.child("computed", name)
357 }
358
359 #[must_use]
360 pub fn effect(&self, name: &str) -> Self {
361 self.child("effect", name)
362 }
363
364 #[must_use]
365 pub fn context(&self, name: &str) -> Self {
366 self.child("context", name)
367 }
368
369 #[must_use]
370 pub fn context_field(&self, name: &str) -> Self {
371 self.child("context-field", name)
372 }
373
374 #[must_use]
375 pub fn provider(&self, name: &str) -> Self {
376 self.child("provider", name)
377 }
378
379 #[must_use]
380 pub fn provider_field(&self, name: &str) -> Self {
381 self.child("provider-field", name)
382 }
383
384 #[must_use]
385 pub fn consumer(&self, name: &str) -> Self {
386 self.child("consumer", name)
387 }
388
389 #[must_use]
390 pub fn consumer_field(&self, name: &str) -> Self {
391 self.child("consumer-field", name)
392 }
393
394 #[must_use]
395 pub fn form(&self, name: &str) -> Self {
396 self.child("form", name)
397 }
398
399 #[must_use]
400 pub fn resource(&self, name: &str) -> Self {
401 self.child("resource", name)
402 }
403
404 #[must_use]
405 pub fn route_loader(&self, name: &str) -> Self {
406 self.child("route-loader", name)
407 }
408
409 #[must_use]
410 pub fn server_action(&self, name: &str) -> Self {
411 self.child("server-action", name)
412 }
413
414 #[must_use]
415 pub fn form_field(&self, name: &str) -> Self {
416 self.child("form-field", name)
417 }
418
419 #[must_use]
420 pub fn form_declaration_candidate_in_module(
421 module_path: impl AsRef<Path>,
422 position: usize,
423 ) -> Self {
424 Self(format!(
425 "module:{}/form-declaration:{position}",
426 normalized_module_path(module_path.as_ref())
427 ))
428 }
429
430 #[must_use]
431 pub fn form_field_declaration_candidate_in_module(
432 module_path: impl AsRef<Path>,
433 position: usize,
434 ) -> Self {
435 Self(format!(
436 "module:{}/form-field-declaration:{position}",
437 normalized_module_path(module_path.as_ref())
438 ))
439 }
440
441 #[must_use]
442 pub fn form_field_binding_candidate_in_module(
443 module_path: impl AsRef<Path>,
444 position: usize,
445 ) -> Self {
446 Self(format!(
447 "module:{}/form-field-binding-candidate:{position}",
448 normalized_module_path(module_path.as_ref())
449 ))
450 }
451
452 #[must_use]
453 pub fn validation_rule_candidate_in_module(
454 module_path: impl AsRef<Path>,
455 position: usize,
456 ) -> Self {
457 Self(format!(
458 "module:{}/validation-rule-candidate:{position}",
459 normalized_module_path(module_path.as_ref())
460 ))
461 }
462
463 #[must_use]
464 pub fn submission_declaration_candidate_in_module(
465 module_path: impl AsRef<Path>,
466 position: usize,
467 ) -> Self {
468 Self(format!(
469 "module:{}/submission-declaration-candidate:{position}",
470 normalized_module_path(module_path.as_ref())
471 ))
472 }
473
474 #[must_use]
475 pub fn field(&self, name: &str) -> Self {
476 self.child("field", name)
477 }
478
479 #[must_use]
480 pub fn validation_rule(&self, ordinal: usize) -> Self {
481 self.child("validation-rule", &ordinal.to_string())
482 }
483
484 #[must_use]
485 pub fn validation_plan(&self) -> Self {
486 Self(format!("{}/validation-plan", self.as_str()))
487 }
488
489 #[must_use]
490 pub fn field_dependency(&self, source_field: &Self) -> Self {
491 self.child("field-dependency", source_field.as_str())
492 }
493
494 #[must_use]
495 pub fn dirty_tracking_plan(&self) -> Self {
496 Self(format!("{}/dirty-plan", self.as_str()))
497 }
498
499 #[must_use]
500 pub fn touched_tracking_plan(&self) -> Self {
501 Self(format!("{}/touched-plan", self.as_str()))
502 }
503
504 #[must_use]
505 pub fn field_tracking(&self) -> Self {
506 Self(format!("{}/tracking", self.as_str()))
507 }
508
509 #[must_use]
510 pub fn submission_plan(&self) -> Self {
511 Self(format!("{}/submission-plan", self.as_str()))
512 }
513
514 #[must_use]
515 pub fn serialization_plan(&self) -> Self {
516 Self(format!("{}/serialization-plan", self.as_str()))
517 }
518
519 #[must_use]
520 pub fn reset_plan(&self) -> Self {
521 Self(format!("{}/reset-plan", self.as_str()))
522 }
523
524 #[must_use]
525 pub fn field_reset_operation(&self, field: &Self) -> Self {
526 self.child("field-reset", field.as_str())
527 }
528
529 #[must_use]
530 pub fn form_instance(&self, form: &str) -> Self {
531 self.child("form-instance", form)
532 }
533
534 #[must_use]
535 pub fn slot(&self, name: &str) -> Self {
536 self.child("slot", name)
537 }
538
539 #[must_use]
540 pub fn slot_field(&self, name: &str) -> Self {
541 self.child("slot-field", name)
542 }
543
544 #[must_use]
545 pub fn slot_declaration_candidate(&self, position: usize) -> Self {
546 self.child("slot-declaration", &position.to_string())
547 }
548
549 #[must_use]
550 pub fn context_declaration_candidate(&self, position: usize) -> Self {
551 self.child("context-declaration", &position.to_string())
552 }
553
554 #[must_use]
556 pub fn context_provider_function(&self) -> Self {
557 self.child("context-source", "evaluation")
558 }
559
560 #[must_use]
562 pub fn context_default_function(&self) -> Self {
563 self.child("context-default-source", "evaluation")
564 }
565
566 #[must_use]
568 pub fn context_consumer_load(&self) -> Self {
569 self.child("context-load", "value")
570 }
571
572 #[must_use]
573 pub fn effect_activation_slot(&self, name: &str) -> Self {
574 self.child("effect-activation", name)
575 }
576
577 #[must_use]
578 pub fn effect_statement(&self, index: usize) -> Self {
579 self.child("statement", &index.to_string())
580 }
581
582 #[must_use]
583 pub fn effect_cleanup_statement(&self, index: usize) -> Self {
584 self.child("cleanup-statement", &index.to_string())
585 }
586
587 #[must_use]
588 pub fn effect_cleanup_program(&self) -> Self {
589 self.child("cleanup", "program")
590 }
591
592 #[must_use]
593 pub fn action(&self, method: &str, index: usize) -> Self {
594 self.child("action", &format!("{method}:{index}"))
595 }
596
597 #[must_use]
601 pub fn action_endpoint(&self, name: &str) -> Self {
602 self.child("action-endpoint", name)
603 }
604
605 #[must_use]
606 pub fn action_batch(&self, method: &str) -> Self {
607 self.child("action-batch", method)
608 }
609
610 #[must_use]
611 pub fn opaque_activation(&self, method: &str) -> Self {
612 self.child("opaque-activation", method)
613 }
614
615 #[must_use]
616 pub fn package_invocation(&self, action: &str) -> Self {
617 self.child("package-invocation", action)
618 }
619
620 #[must_use]
621 pub fn local_variable(&self, name: &str, index: usize) -> Self {
622 self.child("local", &format!("{name}:{index}"))
623 }
624
625 #[must_use]
626 pub fn parameter(&self, name: &str, index: usize) -> Self {
627 self.child("parameter", &format!("{name}:{index}"))
628 }
629
630 #[must_use]
631 pub fn expression(&self, path: &str) -> Self {
632 self.child("expression", path)
633 }
634
635 #[must_use]
636 pub fn semantic_type(&self) -> Self {
637 self.child("type", "semantic")
638 }
639
640 #[must_use]
641 pub fn event_handler(&self, event: &str, index: usize) -> Self {
642 self.child("event", &format!("{event}:{index}"))
643 }
644
645 #[must_use]
646 pub fn template(&self) -> Self {
647 self.child("template", "render")
648 }
649
650 #[must_use]
651 pub fn template_entity(&self, kind: &str, path: &str) -> Self {
652 self.child(kind, path)
653 }
654
655 #[must_use]
656 pub fn component_invocation(&self, target: &str) -> Self {
657 self.child("component-invocation", target)
658 }
659
660 #[must_use]
662 pub fn layout_composition_invocation(&self, route: &Self, position: usize) -> Self {
663 self.child(
664 "layout-composition",
665 &format!("{}:{position}", route.as_str()),
666 )
667 }
668
669 #[must_use]
670 pub fn template_position(&self) -> Self {
671 self.child("template-position", "authored")
672 }
673
674 #[must_use]
675 pub fn field_binding(&self, field: &str) -> Self {
676 self.child("field-binding", field)
677 }
678
679 #[must_use]
680 pub fn slot_content_fragment(&self, slot_name: &str) -> Self {
681 self.child("slot-content", slot_name)
682 }
683
684 #[must_use]
685 pub fn slot_outlet(&self, slot_name: &str) -> Self {
686 self.child("slot-outlet", slot_name)
687 }
688
689 #[must_use]
690 pub fn slot_binding(&self, binding_key: &str) -> Self {
691 self.child("slot-binding", binding_key)
692 }
693
694 #[must_use]
695 pub fn component_instance_invocation(&self, invocation: &str) -> Self {
696 self.child("invocation", invocation)
697 }
698
699 #[must_use]
700 pub fn component_structural_region(&self, kind: &str) -> Self {
701 self.child("component-structural-region", kind)
702 }
703
704 #[must_use]
705 pub fn as_str(&self) -> &str {
706 &self.0
707 }
708
709 fn child(&self, kind: &str, name: &str) -> Self {
710 Self(format!("{}/{kind}:{name}", self.0))
711 }
712}
713
714impl EffectId {
715 #[must_use]
716 pub fn from_semantic(id: &SemanticId) -> Self {
717 Self(id.clone())
718 }
719
720 #[must_use]
721 pub fn as_str(&self) -> &str {
722 self.0.as_str()
723 }
724}
725
726impl EffectStatementId {
727 #[must_use]
728 pub fn from_semantic(id: &SemanticId) -> Self {
729 Self(id.clone())
730 }
731
732 #[must_use]
733 pub fn as_str(&self) -> &str {
734 self.0.as_str()
735 }
736}
737
738impl ContextId {
739 #[must_use]
740 pub fn for_component(component: &SemanticId, name: &str) -> Self {
741 Self(component.context(name))
742 }
743
744 #[must_use]
745 pub const fn as_semantic_id(&self) -> &SemanticId {
746 &self.0
747 }
748
749 #[must_use]
750 pub fn as_str(&self) -> &str {
751 self.0.as_str()
752 }
753}
754
755impl ProviderId {
756 #[must_use]
757 pub fn for_component(component: &SemanticId, name: &str) -> Self {
758 Self(component.provider(name))
759 }
760
761 #[must_use]
762 pub const fn as_semantic_id(&self) -> &SemanticId {
763 &self.0
764 }
765
766 #[must_use]
767 pub fn as_str(&self) -> &str {
768 self.0.as_str()
769 }
770}
771
772impl ConsumerId {
773 #[must_use]
774 pub fn for_component(component: &SemanticId, name: &str) -> Self {
775 Self(component.consumer(name))
776 }
777
778 #[must_use]
779 pub const fn as_semantic_id(&self) -> &SemanticId {
780 &self.0
781 }
782
783 #[must_use]
784 pub fn as_str(&self) -> &str {
785 self.0.as_str()
786 }
787}
788
789impl FormId {
790 #[must_use]
791 pub fn for_owner(owner: &SemanticId, name: &str) -> Self {
792 Self(owner.form(name))
793 }
794
795 #[must_use]
796 pub const fn as_semantic_id(&self) -> &SemanticId {
797 &self.0
798 }
799
800 #[must_use]
801 pub fn as_str(&self) -> &str {
802 self.0.as_str()
803 }
804}
805
806impl ResourceId {
807 #[must_use]
808 pub fn for_owner(owner: &SemanticId, name: &str) -> Self {
809 Self(owner.resource(name))
810 }
811
812 #[must_use]
813 pub const fn as_semantic_id(&self) -> &SemanticId {
814 &self.0
815 }
816
817 #[must_use]
818 pub fn as_str(&self) -> &str {
819 self.0.as_str()
820 }
821}
822
823impl ResourceActivationId {
824 #[must_use]
825 pub fn for_component_instance(instance: &ComponentInstanceId, resource: &ResourceId) -> Self {
826 Self(
827 instance
828 .as_semantic_id()
829 .child("resource-activation", resource.as_str()),
830 )
831 }
832
833 #[must_use]
835 pub fn data_slot(&self) -> SemanticId {
836 self.0.child("resource-slot", "data")
837 }
838
839 #[must_use]
841 pub fn error_slot(&self) -> SemanticId {
842 self.0.child("resource-slot", "error")
843 }
844
845 #[must_use]
847 pub fn state_slot(&self) -> SemanticId {
848 self.0.child("resource-slot", "state")
849 }
850
851 #[must_use]
852 pub const fn as_semantic_id(&self) -> &SemanticId {
853 &self.0
854 }
855
856 #[must_use]
857 pub fn as_str(&self) -> &str {
858 self.0.as_str()
859 }
860}
861
862impl EffectInstanceId {
863 #[must_use]
864 pub fn for_component_instance(instance: &ComponentInstanceId, effect: &SemanticId) -> Self {
865 Self(
866 instance
867 .as_semantic_id()
868 .child("effect-instance", effect.as_str()),
869 )
870 }
871
872 #[must_use]
873 pub const fn as_semantic_id(&self) -> &SemanticId {
874 &self.0
875 }
876
877 #[must_use]
878 pub fn as_str(&self) -> &str {
879 self.0.as_str()
880 }
881}
882
883impl FormInstanceId {
884 #[must_use]
885 pub fn for_component_instance(instance: &ComponentInstanceId, form: &FormId) -> Self {
886 Self(instance.as_semantic_id().form_instance(form.as_str()))
887 }
888
889 #[must_use]
890 pub const fn as_semantic_id(&self) -> &SemanticId {
891 &self.0
892 }
893
894 #[must_use]
895 pub fn as_str(&self) -> &str {
896 self.0.as_str()
897 }
898}
899
900impl FormDeclarationCandidateId {
901 #[must_use]
902 pub fn for_source_position(module_path: impl AsRef<Path>, position: usize) -> Self {
903 Self(SemanticId::form_declaration_candidate_in_module(
904 module_path,
905 position,
906 ))
907 }
908
909 #[must_use]
910 pub const fn as_semantic_id(&self) -> &SemanticId {
911 &self.0
912 }
913
914 #[must_use]
915 pub fn as_str(&self) -> &str {
916 self.0.as_str()
917 }
918}
919
920impl FormFieldDeclarationCandidateId {
921 #[must_use]
922 pub fn for_source_position(module_path: impl AsRef<Path>, position: usize) -> Self {
923 Self(SemanticId::form_field_declaration_candidate_in_module(
924 module_path,
925 position,
926 ))
927 }
928
929 #[must_use]
930 pub const fn as_semantic_id(&self) -> &SemanticId {
931 &self.0
932 }
933
934 #[must_use]
935 pub fn as_str(&self) -> &str {
936 self.0.as_str()
937 }
938}
939
940impl FormFieldBindingCandidateId {
941 #[must_use]
942 pub fn for_source_position(module_path: impl AsRef<Path>, position: usize) -> Self {
943 Self(SemanticId::form_field_binding_candidate_in_module(
944 module_path,
945 position,
946 ))
947 }
948
949 #[must_use]
950 pub const fn as_semantic_id(&self) -> &SemanticId {
951 &self.0
952 }
953
954 #[must_use]
955 pub fn as_str(&self) -> &str {
956 self.0.as_str()
957 }
958}
959
960impl FieldId {
961 #[must_use]
962 pub fn for_form(form: &FormId, name: &str) -> Self {
963 Self(form.as_semantic_id().field(name))
964 }
965
966 #[must_use]
967 pub const fn as_semantic_id(&self) -> &SemanticId {
968 &self.0
969 }
970
971 #[must_use]
972 pub fn as_str(&self) -> &str {
973 self.0.as_str()
974 }
975}
976
977impl FieldBindingId {
978 #[must_use]
979 pub fn for_control(control: &SemanticId, field: &FieldId) -> Self {
980 Self(control.field_binding(field.as_str()))
981 }
982
983 #[must_use]
984 pub const fn as_semantic_id(&self) -> &SemanticId {
985 &self.0
986 }
987
988 #[must_use]
989 pub fn as_str(&self) -> &str {
990 self.0.as_str()
991 }
992}
993
994impl SubmissionHostCandidateId {
995 #[must_use]
996 pub fn for_source_position(module_path: impl AsRef<Path>, position: usize) -> Self {
997 Self(
998 SemanticId::form_field_binding_candidate_in_module(module_path, position)
999 .child("submission-host-candidate", "host"),
1000 )
1001 }
1002
1003 #[must_use]
1004 pub const fn as_semantic_id(&self) -> &SemanticId {
1005 &self.0
1006 }
1007
1008 #[must_use]
1009 pub fn as_str(&self) -> &str {
1010 self.0.as_str()
1011 }
1012}
1013
1014impl SubmissionHostId {
1015 #[must_use]
1016 pub fn for_element(element: &SemanticId, form: &FormId) -> Self {
1017 Self(element.child("submission-host", form.as_str()))
1018 }
1019
1020 #[must_use]
1021 pub const fn as_semantic_id(&self) -> &SemanticId {
1022 &self.0
1023 }
1024
1025 #[must_use]
1026 pub fn as_str(&self) -> &str {
1027 self.0.as_str()
1028 }
1029}
1030
1031impl FormOwnershipGraphId {
1032 #[must_use]
1036 pub fn for_build_roots<'a>(roots: impl IntoIterator<Item = &'a ComponentRootId>) -> Self {
1037 let mut roots = roots
1038 .into_iter()
1039 .map(ComponentRootId::as_str)
1040 .collect::<Vec<_>>();
1041 roots.sort_unstable();
1042 roots.dedup();
1043 let authority = if roots.is_empty() {
1044 "application".to_string()
1045 } else {
1046 roots.join("+")
1047 };
1048 Self(SemanticId(format!("form-ownership-graph:{authority}")))
1049 }
1050
1051 #[must_use]
1052 pub const fn as_semantic_id(&self) -> &SemanticId {
1053 &self.0
1054 }
1055
1056 #[must_use]
1057 pub fn as_str(&self) -> &str {
1058 self.0.as_str()
1059 }
1060}
1061
1062impl ValidationRuleCandidateId {
1063 #[must_use]
1064 pub fn for_source_position(module_path: impl AsRef<Path>, position: usize) -> Self {
1065 Self(SemanticId::validation_rule_candidate_in_module(
1066 module_path,
1067 position,
1068 ))
1069 }
1070
1071 #[must_use]
1072 pub const fn as_semantic_id(&self) -> &SemanticId {
1073 &self.0
1074 }
1075
1076 #[must_use]
1077 pub fn as_str(&self) -> &str {
1078 self.0.as_str()
1079 }
1080}
1081
1082impl ValidationRuleId {
1083 #[must_use]
1084 pub fn for_field(field: &FieldId, authored_ordinal: usize) -> Self {
1085 Self(field.as_semantic_id().validation_rule(authored_ordinal))
1086 }
1087
1088 #[must_use]
1089 pub const fn as_semantic_id(&self) -> &SemanticId {
1090 &self.0
1091 }
1092
1093 #[must_use]
1094 pub fn as_str(&self) -> &str {
1095 self.0.as_str()
1096 }
1097}
1098
1099impl ValidationGraphId {
1100 #[must_use]
1101 pub fn for_build_roots<'a>(roots: impl IntoIterator<Item = &'a ComponentRootId>) -> Self {
1102 let mut roots = roots
1103 .into_iter()
1104 .map(ComponentRootId::as_str)
1105 .collect::<Vec<_>>();
1106 roots.sort_unstable();
1107 roots.dedup();
1108 let authority = if roots.is_empty() {
1109 "application".to_string()
1110 } else {
1111 roots.join("+")
1112 };
1113 Self(SemanticId(format!("validation-graph:{authority}")))
1114 }
1115
1116 #[must_use]
1117 pub const fn as_semantic_id(&self) -> &SemanticId {
1118 &self.0
1119 }
1120
1121 #[must_use]
1122 pub fn as_str(&self) -> &str {
1123 self.0.as_str()
1124 }
1125}
1126
1127impl ValidationPlanId {
1128 #[must_use]
1129 pub fn for_form(form: &FormId) -> Self {
1130 Self(form.as_semantic_id().validation_plan())
1131 }
1132
1133 #[must_use]
1134 pub const fn as_semantic_id(&self) -> &SemanticId {
1135 &self.0
1136 }
1137
1138 #[must_use]
1139 pub fn as_str(&self) -> &str {
1140 self.0.as_str()
1141 }
1142}
1143
1144impl FieldDependencyId {
1145 #[must_use]
1146 pub fn for_rule_and_source(rule: &ValidationRuleId, source_field: &FieldId) -> Self {
1147 Self(
1148 rule.as_semantic_id()
1149 .field_dependency(source_field.as_semantic_id()),
1150 )
1151 }
1152
1153 #[must_use]
1154 pub const fn as_semantic_id(&self) -> &SemanticId {
1155 &self.0
1156 }
1157
1158 #[must_use]
1159 pub fn as_str(&self) -> &str {
1160 self.0.as_str()
1161 }
1162}
1163
1164impl DirtyTrackingPlanId {
1165 #[must_use]
1166 pub fn for_form(form: &FormId) -> Self {
1167 Self(form.as_semantic_id().dirty_tracking_plan())
1168 }
1169
1170 #[must_use]
1171 pub const fn as_semantic_id(&self) -> &SemanticId {
1172 &self.0
1173 }
1174
1175 #[must_use]
1176 pub fn as_str(&self) -> &str {
1177 self.0.as_str()
1178 }
1179}
1180
1181impl TouchedTrackingPlanId {
1182 #[must_use]
1183 pub fn for_form(form: &FormId) -> Self {
1184 Self(form.as_semantic_id().touched_tracking_plan())
1185 }
1186
1187 #[must_use]
1188 pub const fn as_semantic_id(&self) -> &SemanticId {
1189 &self.0
1190 }
1191
1192 #[must_use]
1193 pub fn as_str(&self) -> &str {
1194 self.0.as_str()
1195 }
1196}
1197
1198impl FieldTrackingId {
1199 #[must_use]
1200 pub fn for_field(field: &FieldId) -> Self {
1201 Self(field.as_semantic_id().field_tracking())
1202 }
1203
1204 #[must_use]
1205 pub const fn as_semantic_id(&self) -> &SemanticId {
1206 &self.0
1207 }
1208
1209 #[must_use]
1210 pub fn as_str(&self) -> &str {
1211 self.0.as_str()
1212 }
1213}
1214
1215impl SubmissionDeclarationCandidateId {
1216 #[must_use]
1217 pub fn for_source_position(module_path: impl AsRef<Path>, position: usize) -> Self {
1218 Self(SemanticId::submission_declaration_candidate_in_module(
1219 module_path,
1220 position,
1221 ))
1222 }
1223
1224 #[must_use]
1225 pub const fn as_semantic_id(&self) -> &SemanticId {
1226 &self.0
1227 }
1228
1229 #[must_use]
1230 pub fn as_str(&self) -> &str {
1231 self.0.as_str()
1232 }
1233}
1234
1235impl SubmissionPlanId {
1236 #[must_use]
1237 pub fn for_form(form: &FormId) -> Self {
1238 Self(form.as_semantic_id().submission_plan())
1239 }
1240
1241 #[must_use]
1242 pub const fn as_semantic_id(&self) -> &SemanticId {
1243 &self.0
1244 }
1245
1246 #[must_use]
1247 pub fn as_str(&self) -> &str {
1248 self.0.as_str()
1249 }
1250}
1251
1252impl SerializationPlanId {
1253 #[must_use]
1254 pub fn for_form(form: &FormId) -> Self {
1255 Self(form.as_semantic_id().serialization_plan())
1256 }
1257
1258 #[must_use]
1259 pub const fn as_semantic_id(&self) -> &SemanticId {
1260 &self.0
1261 }
1262
1263 #[must_use]
1264 pub fn as_str(&self) -> &str {
1265 self.0.as_str()
1266 }
1267}
1268
1269impl ResetPlanId {
1270 #[must_use]
1271 pub fn for_form(form: &FormId) -> Self {
1272 Self(form.as_semantic_id().reset_plan())
1273 }
1274 #[must_use]
1275 pub const fn as_semantic_id(&self) -> &SemanticId {
1276 &self.0
1277 }
1278 #[must_use]
1279 pub fn as_str(&self) -> &str {
1280 self.0.as_str()
1281 }
1282}
1283
1284impl FieldResetOperationId {
1285 #[must_use]
1286 pub fn for_plan_and_field(plan: &ResetPlanId, field: &FieldId) -> Self {
1287 Self(
1288 plan.as_semantic_id()
1289 .field_reset_operation(field.as_semantic_id()),
1290 )
1291 }
1292 #[must_use]
1293 pub const fn as_semantic_id(&self) -> &SemanticId {
1294 &self.0
1295 }
1296 #[must_use]
1297 pub fn as_str(&self) -> &str {
1298 self.0.as_str()
1299 }
1300}
1301
1302macro_rules! impl_form_slot_id {
1303 ($name:ident) => {
1304 impl $name {
1305 #[must_use]
1306 pub fn for_instance(instance: &FormInstanceId, name: &str) -> Self {
1307 Self(
1308 instance
1309 .as_semantic_id()
1310 .child("form-slot", &format!("{}:{name}", stringify!($name))),
1311 )
1312 }
1313
1314 #[must_use]
1315 pub const fn as_semantic_id(&self) -> &SemanticId {
1316 &self.0
1317 }
1318
1319 #[must_use]
1320 pub fn as_str(&self) -> &str {
1321 self.0.as_str()
1322 }
1323 }
1324 };
1325}
1326impl_form_slot_id!(FormFieldValueSlotId);
1327impl_form_slot_id!(FormFieldDirtySlotId);
1328impl_form_slot_id!(FormFieldTouchedSlotId);
1329impl_form_slot_id!(FormFieldValidationSlotId);
1330impl_form_slot_id!(FormValidationAggregateSlotId);
1331impl_form_slot_id!(FormSubmissionStateSlotId);
1332
1333impl ValidationDependencyCycleId {
1334 #[must_use]
1335 pub fn for_fields(form: &FormId, fields: &[FieldId]) -> Self {
1336 let mut fields = fields.iter().map(FieldId::as_str).collect::<Vec<_>>();
1337 fields.sort_unstable();
1338 fields.dedup();
1339 Self(SemanticId(format!(
1340 "validation-cycle:{}/{}",
1341 form.as_str(),
1342 fields.join("+")
1343 )))
1344 }
1345
1346 #[must_use]
1347 pub const fn as_semantic_id(&self) -> &SemanticId {
1348 &self.0
1349 }
1350
1351 #[must_use]
1352 pub fn as_str(&self) -> &str {
1353 self.0.as_str()
1354 }
1355}
1356
1357impl SlotId {
1358 #[must_use]
1359 pub fn for_component(component: &SemanticId, name: &str) -> Self {
1360 Self(component.slot(name))
1361 }
1362
1363 #[must_use]
1364 pub const fn as_semantic_id(&self) -> &SemanticId {
1365 &self.0
1366 }
1367
1368 #[must_use]
1369 pub fn as_str(&self) -> &str {
1370 self.0.as_str()
1371 }
1372}
1373
1374impl SlotDeclarationCandidateId {
1375 #[must_use]
1376 pub fn for_component_position(component: &SemanticId, position: usize) -> Self {
1377 Self(component.slot_declaration_candidate(position))
1378 }
1379
1380 #[must_use]
1381 pub const fn as_semantic_id(&self) -> &SemanticId {
1382 &self.0
1383 }
1384
1385 #[must_use]
1386 pub fn as_str(&self) -> &str {
1387 self.0.as_str()
1388 }
1389}
1390
1391impl ComponentInvocationId {
1392 #[must_use]
1393 pub fn for_template_entity(template_entity: &SemanticId, target: &str) -> Self {
1394 Self(template_entity.component_invocation(target))
1395 }
1396
1397 #[must_use]
1400 pub fn for_layout_composition(
1401 layout: &SemanticId,
1402 route_component: &SemanticId,
1403 position: usize,
1404 ) -> Self {
1405 Self(layout.layout_composition_invocation(route_component, position))
1406 }
1407
1408 #[must_use]
1409 pub const fn as_semantic_id(&self) -> &SemanticId {
1410 &self.0
1411 }
1412
1413 #[must_use]
1414 pub fn as_str(&self) -> &str {
1415 self.0.as_str()
1416 }
1417}
1418
1419impl TemplatePositionId {
1420 #[must_use]
1421 pub fn for_template_entity(template_entity: &SemanticId) -> Self {
1422 Self(template_entity.template_position())
1423 }
1424
1425 #[must_use]
1426 pub const fn as_semantic_id(&self) -> &SemanticId {
1427 &self.0
1428 }
1429
1430 #[must_use]
1431 pub fn as_str(&self) -> &str {
1432 self.0.as_str()
1433 }
1434}
1435
1436impl SlotContentFragmentId {
1437 #[must_use]
1438 pub fn for_invocation(invocation: &ComponentInvocationId, slot_name: &str) -> Self {
1439 Self(invocation.as_semantic_id().slot_content_fragment(slot_name))
1440 }
1441
1442 #[must_use]
1443 pub const fn as_semantic_id(&self) -> &SemanticId {
1444 &self.0
1445 }
1446
1447 #[must_use]
1448 pub fn as_str(&self) -> &str {
1449 self.0.as_str()
1450 }
1451}
1452
1453impl SlotOutletId {
1454 #[must_use]
1455 pub fn for_template_entity(template_entity: &SemanticId, slot_name: &str) -> Self {
1456 Self(template_entity.slot_outlet(slot_name))
1457 }
1458
1459 #[must_use]
1460 pub const fn as_semantic_id(&self) -> &SemanticId {
1461 &self.0
1462 }
1463
1464 #[must_use]
1465 pub fn as_str(&self) -> &str {
1466 self.0.as_str()
1467 }
1468}
1469
1470impl SlotBindingId {
1471 #[must_use]
1472 pub fn for_instance(instance: &ComponentInstanceId, binding_key: &str) -> Self {
1473 Self(instance.as_semantic_id().slot_binding(binding_key))
1474 }
1475
1476 #[must_use]
1477 pub const fn as_semantic_id(&self) -> &SemanticId {
1478 &self.0
1479 }
1480
1481 #[must_use]
1482 pub fn as_str(&self) -> &str {
1483 self.0.as_str()
1484 }
1485}
1486
1487impl ComponentRootId {
1488 #[must_use]
1489 pub fn for_component(component: &SemanticId) -> Self {
1490 Self(SemanticId::component_root(component))
1491 }
1492
1493 #[must_use]
1494 pub const fn as_semantic_id(&self) -> &SemanticId {
1495 &self.0
1496 }
1497
1498 #[must_use]
1499 pub fn as_str(&self) -> &str {
1500 self.0.as_str()
1501 }
1502}
1503
1504impl ComponentInstanceId {
1505 #[must_use]
1506 pub fn for_root(root: &ComponentRootId) -> Self {
1507 Self(root.as_semantic_id().clone())
1508 }
1509
1510 #[must_use]
1511 pub fn for_invocation(parent: &Self, invocation: &ComponentInvocationId) -> Self {
1512 Self(
1513 parent
1514 .as_semantic_id()
1515 .component_instance_invocation(invocation.as_str()),
1516 )
1517 }
1518
1519 #[must_use]
1520 pub const fn as_semantic_id(&self) -> &SemanticId {
1521 &self.0
1522 }
1523
1524 #[must_use]
1525 pub fn as_str(&self) -> &str {
1526 self.0.as_str()
1527 }
1528}
1529
1530impl ComponentStructuralRegionId {
1531 #[must_use]
1532 pub fn for_template_entity(entity: &SemanticId, kind: &str) -> Self {
1533 Self(entity.component_structural_region(kind))
1534 }
1535
1536 #[must_use]
1537 pub const fn as_semantic_id(&self) -> &SemanticId {
1538 &self.0
1539 }
1540
1541 #[must_use]
1542 pub fn as_str(&self) -> &str {
1543 self.0.as_str()
1544 }
1545}
1546
1547impl ContextDeclarationCandidateId {
1548 #[must_use]
1549 pub fn for_component_position(component: &SemanticId, position: usize) -> Self {
1550 Self(component.context_declaration_candidate(position))
1551 }
1552
1553 #[must_use]
1554 pub const fn as_semantic_id(&self) -> &SemanticId {
1555 &self.0
1556 }
1557
1558 #[must_use]
1559 pub fn as_str(&self) -> &str {
1560 self.0.as_str()
1561 }
1562}
1563
1564fn normalized_module_path(path: &Path) -> String {
1565 let mut segments = Vec::new();
1566 let absolute = path.is_absolute();
1567
1568 for component in path.components() {
1569 match component {
1570 Component::CurDir | Component::RootDir | Component::Prefix(_) => {}
1571 Component::ParentDir => {
1572 if segments.last().is_some_and(|segment| *segment != "..") {
1573 segments.pop();
1574 } else {
1575 segments.push("..".to_string());
1576 }
1577 }
1578 Component::Normal(segment) => segments.push(segment.to_string_lossy().into_owned()),
1579 }
1580 }
1581
1582 let path = segments.join("/");
1583 if absolute {
1584 format!("/{path}")
1585 } else {
1586 path
1587 }
1588}
1589
1590impl fmt::Display for SemanticId {
1591 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1592 self.0.fmt(formatter)
1593 }
1594}
1595
1596impl fmt::Display for EffectId {
1597 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1598 self.0.fmt(formatter)
1599 }
1600}
1601
1602impl fmt::Display for EffectStatementId {
1603 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1604 self.0.fmt(formatter)
1605 }
1606}
1607
1608impl fmt::Display for ContextId {
1609 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1610 self.0.fmt(formatter)
1611 }
1612}
1613
1614impl fmt::Display for ProviderId {
1615 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1616 self.0.fmt(formatter)
1617 }
1618}
1619
1620impl fmt::Display for ConsumerId {
1621 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1622 self.0.fmt(formatter)
1623 }
1624}
1625
1626impl fmt::Display for FormId {
1627 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1628 self.0.fmt(formatter)
1629 }
1630}
1631
1632impl fmt::Display for FormInstanceId {
1633 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1634 self.0.fmt(formatter)
1635 }
1636}
1637
1638impl fmt::Display for FormDeclarationCandidateId {
1639 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1640 self.0.fmt(formatter)
1641 }
1642}
1643
1644impl fmt::Display for FormFieldDeclarationCandidateId {
1645 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1646 self.0.fmt(formatter)
1647 }
1648}
1649
1650impl fmt::Display for FormFieldBindingCandidateId {
1651 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1652 self.0.fmt(formatter)
1653 }
1654}
1655
1656impl fmt::Display for FieldId {
1657 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1658 self.0.fmt(formatter)
1659 }
1660}
1661
1662impl fmt::Display for FieldBindingId {
1663 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1664 self.0.fmt(formatter)
1665 }
1666}
1667
1668impl fmt::Display for SubmissionHostCandidateId {
1669 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1670 self.0.fmt(formatter)
1671 }
1672}
1673impl fmt::Display for SubmissionHostId {
1674 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1675 self.0.fmt(formatter)
1676 }
1677}
1678
1679impl fmt::Display for FormOwnershipGraphId {
1680 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1681 self.0.fmt(formatter)
1682 }
1683}
1684
1685impl fmt::Display for ValidationRuleCandidateId {
1686 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1687 self.0.fmt(formatter)
1688 }
1689}
1690
1691impl fmt::Display for ValidationRuleId {
1692 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1693 self.0.fmt(formatter)
1694 }
1695}
1696
1697impl fmt::Display for ValidationGraphId {
1698 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1699 self.0.fmt(formatter)
1700 }
1701}
1702
1703impl fmt::Display for ValidationPlanId {
1704 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1705 self.0.fmt(formatter)
1706 }
1707}
1708
1709impl fmt::Display for FieldDependencyId {
1710 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1711 self.0.fmt(formatter)
1712 }
1713}
1714
1715impl fmt::Display for ValidationDependencyCycleId {
1716 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1717 self.0.fmt(formatter)
1718 }
1719}
1720
1721impl fmt::Display for SlotId {
1722 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1723 self.0.fmt(formatter)
1724 }
1725}
1726
1727impl fmt::Display for SlotDeclarationCandidateId {
1728 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1729 self.0.fmt(formatter)
1730 }
1731}
1732
1733impl fmt::Display for ComponentInvocationId {
1734 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1735 self.0.fmt(formatter)
1736 }
1737}
1738
1739impl fmt::Display for TemplatePositionId {
1740 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1741 self.0.fmt(formatter)
1742 }
1743}
1744
1745impl fmt::Display for SlotContentFragmentId {
1746 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1747 self.0.fmt(formatter)
1748 }
1749}
1750
1751impl fmt::Display for SlotOutletId {
1752 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1753 self.0.fmt(formatter)
1754 }
1755}
1756
1757impl fmt::Display for SlotBindingId {
1758 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1759 self.0.fmt(formatter)
1760 }
1761}
1762
1763impl fmt::Display for ComponentRootId {
1764 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1765 self.0.fmt(formatter)
1766 }
1767}
1768
1769impl fmt::Display for ComponentInstanceId {
1770 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1771 self.0.fmt(formatter)
1772 }
1773}
1774
1775impl fmt::Display for ComponentStructuralRegionId {
1776 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1777 self.0.fmt(formatter)
1778 }
1779}
1780
1781impl fmt::Display for ContextDeclarationCandidateId {
1782 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1783 self.0.fmt(formatter)
1784 }
1785}
1786
1787#[cfg(test)]
1788mod tests {
1789 use super::{
1790 ComponentInstanceId, ComponentInvocationId, ConsumerId, ContextId, FieldDependencyId,
1791 FieldId, FormId, FormInstanceId, ProviderId, SemanticId, SemanticOwner, SlotId,
1792 TemplatePositionId, ValidationPlanId, ValidationRuleId,
1793 };
1794
1795 #[test]
1796 fn derives_component_scoped_ids() {
1797 let component = SemanticId::component(Some("x-counter"), "Counter");
1798
1799 assert_eq!(component.as_str(), "component:x-counter");
1800 assert_eq!(
1801 component.state_field("count").as_str(),
1802 "component:x-counter/state:count"
1803 );
1804 assert_eq!(
1805 component.method("increment").as_str(),
1806 "component:x-counter/method:increment"
1807 );
1808 assert_eq!(
1809 component.computed("remainingCount").as_str(),
1810 "component:x-counter/computed:remainingCount"
1811 );
1812 assert_eq!(
1813 component.effect("syncTitle").as_str(),
1814 "component:x-counter/effect:syncTitle"
1815 );
1816 assert_eq!(
1817 ContextId::for_component(&component, "theme").as_str(),
1818 "component:x-counter/context:theme"
1819 );
1820 assert_eq!(
1821 ProviderId::for_component(&component, "providedTheme").as_str(),
1822 "component:x-counter/provider:providedTheme"
1823 );
1824 assert_eq!(
1825 ConsumerId::for_component(&component, "theme").as_str(),
1826 "component:x-counter/consumer:theme"
1827 );
1828 assert_eq!(
1829 SlotId::for_component(&component, "children").as_str(),
1830 "component:x-counter/slot:children"
1831 );
1832 assert_eq!(
1833 component.effect_activation_slot("syncTitle").as_str(),
1834 "component:x-counter/effect-activation:syncTitle"
1835 );
1836 assert_eq!(
1837 component.action("increment", 0).as_str(),
1838 "component:x-counter/action:increment:0"
1839 );
1840 assert_eq!(
1841 component
1842 .method("render")
1843 .local_variable("title", 0)
1844 .as_str(),
1845 "component:x-counter/method:render/local:title:0"
1846 );
1847 assert_eq!(
1848 component.event_handler("click", 0).as_str(),
1849 "component:x-counter/event:click:0"
1850 );
1851 assert_eq!(
1852 component.template().as_str(),
1853 "component:x-counter/template:render"
1854 );
1855 let element = component.template().template_entity("element", "root.0");
1856 assert_eq!(
1857 TemplatePositionId::for_template_entity(&element).as_str(),
1858 "component:x-counter/template:render/element:root.0/template-position:authored"
1859 );
1860 assert_eq!(
1861 ComponentInvocationId::for_template_entity(&element, "component:x-card").as_str(),
1862 "component:x-counter/template:render/element:root.0/component-invocation:component:x-card"
1863 );
1864 }
1865
1866 #[test]
1867 fn derives_module_qualified_component_ids() {
1868 let component =
1869 SemanticId::component_in_module("src/../src/Counter.tsx", Some("x-counter"), "Counter");
1870
1871 assert_eq!(
1872 component.as_str(),
1873 "module:src/Counter.tsx/component:x-counter"
1874 );
1875 assert_eq!(
1876 component.state_field("count").as_str(),
1877 "module:src/Counter.tsx/component:x-counter/state:count"
1878 );
1879 assert_eq!(
1880 SemanticId::environment_read_in_module("src/../src/environment.ts", 41).as_str(),
1881 "module:src/environment.ts/environment-read:41"
1882 );
1883 }
1884
1885 #[test]
1886 fn derives_distinct_form_definition_instance_and_field_identities() {
1887 let component =
1888 SemanticId::component_in_module("src/Profile.tsx", Some("x-profile"), "Profile");
1889 let component_instance = serde_json::from_str::<ComponentInstanceId>(
1890 r#""root:module:src/Profile.tsx/component:x-profile""#,
1891 )
1892 .expect("canonical component instance id");
1893 let form = FormId::for_owner(&component, "profile");
1894 let instance = FormInstanceId::for_component_instance(&component_instance, &form);
1895 let nested_component_instance = serde_json::from_str::<ComponentInstanceId>(
1896 r#""root:module:src/Profile.tsx/component:x-profile/invocation:nested""#,
1897 )
1898 .expect("canonical nested component instance id");
1899 let nested_instance =
1900 FormInstanceId::for_component_instance(&nested_component_instance, &form);
1901 let field = FieldId::for_form(&form, "email");
1902 let rule = ValidationRuleId::for_field(&field, 2);
1903 let plan = ValidationPlanId::for_form(&form);
1904 let dependency = FieldDependencyId::for_rule_and_source(&rule, &field);
1905
1906 assert_eq!(
1907 form.as_str(),
1908 "module:src/Profile.tsx/component:x-profile/form:profile"
1909 );
1910 assert_eq!(
1911 field.as_str(),
1912 "module:src/Profile.tsx/component:x-profile/form:profile/field:email"
1913 );
1914 assert_eq!(
1915 instance.as_str(),
1916 "root:module:src/Profile.tsx/component:x-profile/form-instance:module:src/Profile.tsx/component:x-profile/form:profile"
1917 );
1918 assert_ne!(form.as_semantic_id(), field.as_semantic_id());
1919 assert_ne!(form.as_semantic_id(), instance.as_semantic_id());
1920 assert_ne!(field.as_semantic_id(), instance.as_semantic_id());
1921 assert_ne!(instance, nested_instance);
1922 assert_eq!(
1923 plan.as_str(),
1924 "module:src/Profile.tsx/component:x-profile/form:profile/validation-plan"
1925 );
1926 assert_eq!(
1927 dependency.as_str(),
1928 "module:src/Profile.tsx/component:x-profile/form:profile/field:email/validation-rule:2/field-dependency:module:src/Profile.tsx/component:x-profile/form:profile/field:email"
1929 );
1930 }
1931
1932 #[test]
1933 fn falls_back_to_class_name_for_invalid_components() {
1934 assert_eq!(
1935 SemanticId::component(None, "MissingDecorator").as_str(),
1936 "component:MissingDecorator"
1937 );
1938 }
1939
1940 #[test]
1941 fn distinguishes_application_roots_from_entity_owners() {
1942 let component = SemanticId::component(Some("x-counter"), "Counter");
1943
1944 assert_eq!(SemanticOwner::Application.entity_id(), None);
1945 assert_eq!(
1946 SemanticOwner::entity(component.clone()).entity_id(),
1947 Some(&component)
1948 );
1949 }
1950}