Skip to main content

morphir_core/ir/layout/
mod.rs

1//! The document-tree layout: the storage-profile boundary, the logical path grammar, and file
2//! stems.
3//!
4//! Mirrors `IR/src/layout/{index,paths,stems,write-tree}.ts` in `ecosystem/morphir-typescript`;
5//! see `.dev/docs/superpowers/maps/2026-09-17-reference-tree-layout-map.md`. [`paths`] and
6//! [`stems`] supply what a tree reader and a tree writer are both built on; [`read`] assembles a
7//! tree into a distribution and [`write`] lays one back out.
8//!
9//! The same layout holds a v4 distribution ([`read_tree`], [`write_tree`]) or a classic v3
10//! `Library` or `Specs` one ([`read_tree_v3`], [`write_tree_v3`]), whose files all say
11//! `formatVersion: "3.1.0"`; [`read_any_tree`] reads either, chosen by the manifest.
12
13pub mod paths;
14pub mod read;
15pub mod stems;
16pub mod write;
17
18mod model;
19mod v3_model;
20mod v4_model;
21
22pub use paths::{
23    MANIFEST, NodeFileKind, PathKind, Root, VERSION_SLOT, classify, from_physical, module_dir,
24    module_dir_prefix, module_manifest_path, node_file_path, package_dir, to_physical,
25};
26pub use read::read_tree;
27pub use stems::{StemResult, stem_for};
28pub use v3_model::{
29    AnyTree, V3_TREE_FORMAT_VERSION, V3Kind, read_any_tree, read_tree_v3, read_v3_manifest_file,
30    write_tree_v3, write_v3_definition_module, write_v3_manifest, write_v3_specification_module,
31};
32pub use write::{
33    ManifestHeader, TreePolicy, write_definition_module, write_manifest, write_manifest_header,
34    write_specification_module, write_tree,
35};
36
37use crate::ir::Diagnostic;
38
39/// The two storage profiles a document tree can be laid out under.
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub enum Profile {
42    Json,
43    Yaml,
44}
45
46impl Profile {
47    /// The profile's name, as the adapter protocol and the manifest's `profile` field spell it.
48    pub fn name(self) -> &'static str {
49        match self {
50            Profile::Json => "json",
51            Profile::Yaml => "yaml",
52        }
53    }
54
55    /// The extension [`to_physical`] appends for this profile.
56    pub fn extension(self) -> &'static str {
57        match self {
58            Profile::Json => ".json",
59            Profile::Yaml => ".yaml",
60        }
61    }
62
63    /// Reads one file's text as a JSON value tree under this profile.
64    pub fn read(self, text: &str) -> Result<serde_json::Value, Diagnostic> {
65        match self {
66            Profile::Json => crate::ir::json::read(text),
67            Profile::Yaml => crate::ir::yaml::read(text),
68        }
69    }
70
71    /// Writes a JSON value tree as this profile's canonical text.
72    ///
73    /// JSON writes one line with no trailing newline; YAML writes exactly one trailing `\n`.
74    pub fn write(self, value: &serde_json::Value) -> String {
75        match self {
76            Profile::Json => crate::ir::json::write_canonical(value),
77            Profile::Yaml => crate::ir::yaml::write_canonical(value),
78        }
79    }
80}
81
82/// An in-memory document tree: logical path to file text, ordered so a byte-for-byte comparison
83/// of two trees does not depend on insertion order.
84pub type Tree = std::collections::BTreeMap<String, String>;