修复资源依赖本地身份解析
资源依赖图同时索引远端资源身份和 local-asset 本地资源身份 本地 canonical 引用与远端候选去重后再建立依赖连线 补充本地身份解析与候选不歧义回归测试 更新资源自由画板技术方案的依赖身份合同
This commit is contained in:
@@ -400,6 +400,12 @@ pub(crate) fn build_project_resource_graph(
|
|||||||
.push(resource_ids[0].clone());
|
.push(resource_ids[0].clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resources_by_manifest_asset_id = resource_ids_by_manifest_asset
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, resource_ids)| resource_ids.len() == 1)
|
||||||
|
.map(|(asset_id, resource_ids)| (asset_id.clone(), resource_ids[0].clone()))
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
let mut unresolved_reference_resource_ids = BTreeSet::new();
|
let mut unresolved_reference_resource_ids = BTreeSet::new();
|
||||||
let mut reference_edge_by_id = BTreeMap::<String, ProjectResourceReferenceEdge>::new();
|
let mut reference_edge_by_id = BTreeMap::<String, ProjectResourceReferenceEdge>::new();
|
||||||
for (asset_id, target_resource_ids) in &resource_ids_by_manifest_asset {
|
for (asset_id, target_resource_ids) in &resource_ids_by_manifest_asset {
|
||||||
@@ -418,16 +424,32 @@ pub(crate) fn build_project_resource_graph(
|
|||||||
.filter(|value| !value.is_empty())
|
.filter(|value| !value.is_empty())
|
||||||
.collect::<BTreeSet<_>>()
|
.collect::<BTreeSet<_>>()
|
||||||
{
|
{
|
||||||
let source_candidates = resources_by_external_id
|
let mut source_candidates = resources_by_external_id
|
||||||
.get(external_reference_id)
|
.get(external_reference_id)
|
||||||
.map(Vec::as_slice)
|
.map(Vec::as_slice)
|
||||||
.unwrap_or(&[]);
|
.unwrap_or(&[])
|
||||||
|
.iter()
|
||||||
|
.collect::<BTreeSet<_>>();
|
||||||
|
if let Some(referenced_asset_id) = external_reference_id
|
||||||
|
.strip_prefix("local-asset:")
|
||||||
|
.map(str::trim)
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
|
{
|
||||||
|
if let Some(source_resource_id) =
|
||||||
|
resources_by_manifest_asset_id.get(referenced_asset_id)
|
||||||
|
{
|
||||||
|
source_candidates.insert(source_resource_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
if source_candidates.len() != 1 {
|
if source_candidates.len() != 1 {
|
||||||
unresolved_reference_resource_ids.insert(external_reference_id.to_string());
|
unresolved_reference_resource_ids.insert(external_reference_id.to_string());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let source_resource_id = &source_candidates[0];
|
let source_resource_id = source_candidates
|
||||||
if !resource_by_id.contains_key(source_resource_id)
|
.iter()
|
||||||
|
.next()
|
||||||
|
.expect("a non-empty candidate set must have one resource");
|
||||||
|
if !resource_by_id.contains_key(source_resource_id.as_str())
|
||||||
|| !resource_by_id.contains_key(target_resource_id)
|
|| !resource_by_id.contains_key(target_resource_id)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -438,7 +460,7 @@ pub(crate) fn build_project_resource_graph(
|
|||||||
ProjectResourceReferenceEdge {
|
ProjectResourceReferenceEdge {
|
||||||
id,
|
id,
|
||||||
kind: "asset-reference".to_string(),
|
kind: "asset-reference".to_string(),
|
||||||
source_resource_id: source_resource_id.clone(),
|
source_resource_id: source_resource_id.to_string(),
|
||||||
target_resource_id: target_resource_id.clone(),
|
target_resource_id: target_resource_id.clone(),
|
||||||
cyclic: false,
|
cyclic: false,
|
||||||
},
|
},
|
||||||
@@ -835,6 +857,75 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn graph_resolves_local_asset_reference_identities() {
|
||||||
|
let manifest = manifest(
|
||||||
|
Vec::new(),
|
||||||
|
vec![
|
||||||
|
asset("source-1", None, &[], None),
|
||||||
|
asset(
|
||||||
|
"derivative-1",
|
||||||
|
Some("local-asset:derivative-1"),
|
||||||
|
&["local-asset:source-1"],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let graph = build_project_resource_graph(
|
||||||
|
&manifest,
|
||||||
|
vec![
|
||||||
|
resource("asset:source-1", Some("source-1"), None),
|
||||||
|
resource("asset:derivative-1", Some("derivative-1"), None),
|
||||||
|
],
|
||||||
|
&[],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(graph.reference_edges.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
graph.reference_edges[0].source_resource_id,
|
||||||
|
"asset:source-1"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
graph.reference_edges[0].target_resource_id,
|
||||||
|
"asset:derivative-1"
|
||||||
|
);
|
||||||
|
assert!(graph.unresolved_reference_resource_ids.is_empty());
|
||||||
|
assert!(graph
|
||||||
|
.connection_index
|
||||||
|
.iter()
|
||||||
|
.any(|index| index.resource_id == "asset:derivative-1"
|
||||||
|
&& index.upstream_reference_resource_ids == vec!["asset:source-1"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn graph_resolves_local_asset_identity_without_ambiguous_remote_duplicate() {
|
||||||
|
let manifest = manifest(
|
||||||
|
Vec::new(),
|
||||||
|
vec![
|
||||||
|
asset("source-1", Some("external-source"), &[], None),
|
||||||
|
asset(
|
||||||
|
"derivative-1",
|
||||||
|
Some("local-asset:derivative-1"),
|
||||||
|
&["local-asset:source-1"],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let graph = build_project_resource_graph(
|
||||||
|
&manifest,
|
||||||
|
vec![
|
||||||
|
resource("asset:source-1", Some("source-1"), None),
|
||||||
|
resource("asset:derivative-1", Some("derivative-1"), None),
|
||||||
|
],
|
||||||
|
&[],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(graph.reference_edges.len(), 1);
|
||||||
|
assert!(graph.unresolved_reference_resource_ids.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn graph_aggregates_flows_filters_missing_resources_and_detects_cycles_iteratively() {
|
fn graph_aggregates_flows_filters_missing_resources_and_detects_cycles_iteratively() {
|
||||||
let manifest = manifest(
|
let manifest = manifest(
|
||||||
|
|||||||
Reference in New Issue
Block a user