Skip to main content

xidl_parser/versioning/map/
mod.rs

1//! Language-neutral facts describing adjacent API-version changes.
2
3mod collect;
4mod compare;
5mod helpers;
6mod model;
7
8use super::{VersionId, VersioningRecord};
9use crate::error::ParserResult;
10use crate::hir::Specification;
11use serde_json;
12use std::collections::BTreeMap;
13
14pub use model::{Change, ChangeKind, MapStep, MapVersion, TypeChange, VersionMap};
15
16/// Computes the complete, unselected version map for a validated contract.
17pub fn from_spec(
18    spec: &Specification,
19    record: &VersioningRecord,
20    contract: impl Into<String>,
21) -> ParserResult<VersionMap> {
22    from_spec_with_http(spec, record, contract, true)
23}
24
25/// Computes a version map while optionally collecting REST operation facts.
26///
27/// JSON-RPC generators pass `false`: a REST projection would otherwise invent
28/// HTTP routes for ordinary RPC interfaces. Type and declaration facts remain
29/// protocol-independent in both modes.
30pub fn from_spec_with_http(
31    spec: &Specification,
32    record: &VersioningRecord,
33    contract: impl Into<String>,
34    include_http_operations: bool,
35) -> ParserResult<VersionMap> {
36    let versions = record
37        .timeline()
38        .iter()
39        .map(|(_, version)| MapVersion {
40            id: version.ident.clone(),
41            value: version.value.clone(),
42        })
43        .collect::<Vec<_>>();
44    let mut steps = Vec::new();
45    for index in 0..versions.len().saturating_sub(1) {
46        let from_id = VersionId::from_index(index);
47        let to_id = VersionId::from_index(index + 1);
48        let from = record.project(spec, from_id)?;
49        let to = record.project(spec, to_id)?;
50        let operations = if include_http_operations {
51            compare::compare_operations(
52                &collect::collect_operations(&from)?,
53                &collect::collect_operations(&to)?,
54            )
55        } else {
56            BTreeMap::new()
57        };
58        steps.push(MapStep {
59            from: versions[index].id.clone(),
60            to: versions[index + 1].id.clone(),
61            types: compare::compare_types(
62                &collect::collect_types(&from),
63                &collect::collect_types(&to),
64            ),
65            operations,
66        });
67    }
68    Ok(VersionMap {
69        format: 1,
70        contract: contract.into(),
71        versions,
72        steps,
73    })
74}
75
76/// Serializes a version map with the repository's canonical JSON policy.
77pub fn to_json(map: &VersionMap) -> Result<String, serde_json::Error> {
78    let mut content = serde_json::to_string_pretty(map)?;
79    content.push('\n');
80    Ok(content)
81}