sdk

Radroots SDK and bindings
git clone https://radroots.dev/git/sdk.git
Log | Files | Refs | README

commit 25d556cc18d69229df5d688b4062d9e30d0e9d2f
parent abccef4bc45a47e357dd2841b2111db638055cee
Author: triesap <tyson@radroots.org>
Date:   Sat, 27 Jun 2026 20:47:15 +0000

xtask: validate dto import overrides

- pin dto_bindgen to the checked registry API revision
- validate external override targets against generated package exports
- reject local emission for types configured as source-owned imports
- regenerate trade bindings with RadrootsTradeWorkflowState

Diffstat:
MCargo.lock | 10+++++-----
MCargo.toml | 4++--
Mcrates/trade_bindings/src/lib.rs | 7+++++--
Mpackages/trade-bindings/src/generated/types.ts | 2++
Mtools/xtask/src/dto_roots.rs | 421++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
5 files changed, 367 insertions(+), 77 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -502,7 +502,7 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "dto_bindgen" version = "0.1.0" -source = "git+https://github.com/triesap/dto_bindgen?rev=d722db31f56e4c62c423adcf19eaf9029780a017#d722db31f56e4c62c423adcf19eaf9029780a017" +source = "git+https://github.com/triesap/dto_bindgen?rev=e1ec30465ffdb0964908d12f36f7a49f642321db#e1ec30465ffdb0964908d12f36f7a49f642321db" dependencies = [ "dto_bindgen_backend_python", "dto_bindgen_backend_ts", @@ -514,7 +514,7 @@ dependencies = [ [[package]] name = "dto_bindgen_backend_python" version = "0.1.0" -source = "git+https://github.com/triesap/dto_bindgen?rev=d722db31f56e4c62c423adcf19eaf9029780a017#d722db31f56e4c62c423adcf19eaf9029780a017" +source = "git+https://github.com/triesap/dto_bindgen?rev=e1ec30465ffdb0964908d12f36f7a49f642321db#e1ec30465ffdb0964908d12f36f7a49f642321db" dependencies = [ "dto_bindgen_core", ] @@ -522,7 +522,7 @@ dependencies = [ [[package]] name = "dto_bindgen_backend_ts" version = "0.1.0" -source = "git+https://github.com/triesap/dto_bindgen?rev=d722db31f56e4c62c423adcf19eaf9029780a017#d722db31f56e4c62c423adcf19eaf9029780a017" +source = "git+https://github.com/triesap/dto_bindgen?rev=e1ec30465ffdb0964908d12f36f7a49f642321db#e1ec30465ffdb0964908d12f36f7a49f642321db" dependencies = [ "dto_bindgen_core", ] @@ -530,7 +530,7 @@ dependencies = [ [[package]] name = "dto_bindgen_core" version = "0.1.0" -source = "git+https://github.com/triesap/dto_bindgen?rev=d722db31f56e4c62c423adcf19eaf9029780a017#d722db31f56e4c62c423adcf19eaf9029780a017" +source = "git+https://github.com/triesap/dto_bindgen?rev=e1ec30465ffdb0964908d12f36f7a49f642321db#e1ec30465ffdb0964908d12f36f7a49f642321db" dependencies = [ "proc-macro2", "quote", @@ -544,7 +544,7 @@ dependencies = [ [[package]] name = "dto_bindgen_macros" version = "0.1.0" -source = "git+https://github.com/triesap/dto_bindgen?rev=d722db31f56e4c62c423adcf19eaf9029780a017#d722db31f56e4c62c423adcf19eaf9029780a017" +source = "git+https://github.com/triesap/dto_bindgen?rev=e1ec30465ffdb0964908d12f36f7a49f642321db#e1ec30465ffdb0964908d12f36f7a49f642321db" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml @@ -26,8 +26,8 @@ homepage = "https://radroots.org" readme = "README" [workspace.dependencies] -dto_bindgen = { git = "https://github.com/triesap/dto_bindgen", rev = "d722db31f56e4c62c423adcf19eaf9029780a017" } -dto_bindgen_core = { git = "https://github.com/triesap/dto_bindgen", rev = "d722db31f56e4c62c423adcf19eaf9029780a017", package = "dto_bindgen_core" } +dto_bindgen = { git = "https://github.com/triesap/dto_bindgen", rev = "e1ec30465ffdb0964908d12f36f7a49f642321db" } +dto_bindgen_core = { git = "https://github.com/triesap/dto_bindgen", rev = "e1ec30465ffdb0964908d12f36f7a49f642321db", package = "dto_bindgen_core" } radroots_core = { path = "../lib/crates/core", version = "0.1.0-alpha.2", default-features = false } radroots_authority = { path = "../lib/crates/authority", version = "0.1.0-alpha.2", default-features = false } radroots_event_store = { path = "../lib/crates/event_store", version = "0.1.0-alpha.2", default-features = false } diff --git a/crates/trade_bindings/src/lib.rs b/crates/trade_bindings/src/lib.rs @@ -73,6 +73,7 @@ pub const TRADE_TYPE_INVENTORY: &[TradeTypeInventoryEntry] = &[ local_shape("RadrootsTradeReviewQueueEntry"), local_shape("RadrootsTradeReviewStatus"), local_shape("RadrootsTradeSortDirection"), + source_root("RadrootsTradeWorkflowState"), ]; pub const TRADE_LARGE_INTEGER_POLICIES: &[TradeLargeIntegerPolicyEntry] = &[ @@ -219,7 +220,8 @@ mod tests { "RadrootsTradeReviewPriority", "RadrootsTradeReviewQueueEntry", "RadrootsTradeReviewStatus", - "RadrootsTradeSortDirection" + "RadrootsTradeSortDirection", + "RadrootsTradeWorkflowState" ] ); } @@ -256,7 +258,8 @@ mod tests { [ "RadrootsTradeListing", "RadrootsTradeListingSubtotal", - "RadrootsTradeListingTotal" + "RadrootsTradeListingTotal", + "RadrootsTradeWorkflowState" ] ); } diff --git a/packages/trade-bindings/src/generated/types.ts b/packages/trade-bindings/src/generated/types.ts @@ -101,3 +101,5 @@ export type RadrootsTradeReviewQueueEntry = { queue: string, priority: RadrootsT export type RadrootsTradeReviewStatus = "queued" | "in_progress" | "blocked" | "resolved"; export type RadrootsTradeSortDirection = "asc" | "desc"; + +export type RadrootsTradeWorkflowState = "missing" | "requested" | "revision_proposed" | "agreed_pending_rhi" | "committed" | "declined" | "cancelled" | "invalid"; diff --git a/tools/xtask/src/dto_roots.rs b/tools/xtask/src/dto_roots.rs @@ -1,4 +1,6 @@ -use dto_bindgen_core::{Registry, RootDescriptor, TypeDef, TypeId, build_registry}; +use std::collections::{BTreeMap, BTreeSet}; + +use dto_bindgen_core::{Registry, RootDescriptor, build_registry}; use crate::dto_render::{DtoRegistryRenderOptions, DtoTypesModule, render_registry_types}; @@ -32,6 +34,19 @@ pub struct SdkLocalWrapperAllowance { pub reason: &'static str, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct DtoExternalOverride { + target_type: &'static str, + import_name: &'static str, + from_package_key: &'static str, + from: &'static str, +} + +const CORE_BINDINGS_PACKAGE_KEY: &str = "core"; +const CORE_BINDINGS_PACKAGE_NAME: &str = "@radroots/core-bindings"; +const EVENTS_BINDINGS_PACKAGE_KEY: &str = "events"; +const EVENTS_BINDINGS_PACKAGE_NAME: &str = "@radroots/events-bindings"; + pub const DTO_PACKAGE_ROOTS: &[DtoPackageRootSet] = &[ DtoPackageRootSet { package_key: "core", @@ -121,6 +136,41 @@ pub const SDK_LOCAL_WRAPPER_ALLOWANCES: &[SdkLocalWrapperAllowance] = &[ }, ]; +const TRADE_EXTERNAL_OVERRIDES: &[DtoExternalOverride] = &[ + core_override("RadrootsCoreCurrency"), + core_override("RadrootsCoreDecimal"), + core_override("RadrootsCoreDiscount"), + core_override("RadrootsCoreDiscountValue"), + core_override("RadrootsCoreMoney"), + core_override("RadrootsCoreQuantity"), + core_override("RadrootsCoreQuantityPrice"), + core_override("RadrootsCoreUnit"), + events_override("RadrootsFarmRef"), + events_override("RadrootsListing"), + events_override("RadrootsListingAvailability"), + events_override("RadrootsListingBin"), + events_override("RadrootsListingDeliveryMethod"), + events_override("RadrootsListingImage"), + events_override("RadrootsListingProduct"), + events_override("RadrootsListingPublicLocation"), + events_override("RadrootsListingStatus"), + events_override("RadrootsNostrEventPtr"), + events_override("RadrootsOrderCancellation"), + events_override("RadrootsOrderDecision"), + events_override("RadrootsPlotRef"), + events_override("RadrootsResourceAreaRef"), + events_override("RadrootsOrderEconomicLine"), + events_override("RadrootsOrderItem"), + events_override("RadrootsOrderRequest"), + events_override("RadrootsOrderRevisionDecision"), + events_override("RadrootsOrderRevisionProposal"), + events_override("RadrootsTradeListingValidateRequest"), + events_override("RadrootsTradeListingValidateResult"), +]; + +const TRADE_REQUIRED_EXTERNAL_PACKAGE_IMPORTS: &[&str] = + &[CORE_BINDINGS_PACKAGE_NAME, EVENTS_BINDINGS_PACKAGE_NAME]; + pub fn package_root_set(package_key: &str) -> Option<&'static DtoPackageRootSet> { DTO_PACKAGE_ROOTS .iter() @@ -144,10 +194,8 @@ pub fn events_types_module() -> Result<DtoTypesModule, String> { let root_set = package_root_set("events").ok_or_else(|| "missing events DTO roots".to_owned())?; let registry = root_set.registry(); - let rendered = render_registry_types( - &registry, - &core_import_options(&registry, DtoRegistryRenderOptions::default()), - )?; + let options = core_import_options(&registry, DtoRegistryRenderOptions::default())?; + let rendered = render_registry_types(&registry, &options)?; Ok(DtoTypesModule::new( rendered.imports_ts().unwrap_or_default(), with_events_sdk_wrappers(rendered.body_ts()), @@ -175,10 +223,10 @@ pub fn replica_db_schema_types_module() -> Result<DtoTypesModule, String> { pub fn trade_types_module() -> Result<DtoTypesModule, String> { let root_set = package_root_set("trade").ok_or_else(|| "missing trade DTO roots".to_owned())?; let registry = root_set.registry(); - render_registry_types( - &registry, - &trade_import_options(DtoRegistryRenderOptions::default()), - ) + let options = trade_import_options(DtoRegistryRenderOptions::default())?; + let rendered = render_registry_types(&registry, &options)?; + validate_external_override_usage(&rendered, TRADE_EXTERNAL_OVERRIDES)?; + Ok(rendered) } pub fn types_types_module() -> Result<DtoTypesModule, String> { @@ -211,10 +259,8 @@ fn types_roots() -> Vec<RootDescriptor> { fn core_import_options( registry: &Registry, mut options: DtoRegistryRenderOptions, -) -> DtoRegistryRenderOptions { +) -> Result<DtoRegistryRenderOptions, String> { for export_name in [ - "RadrootsCoreCurrency", - "RadrootsCoreDecimal", "RadrootsCoreDiscount", "RadrootsCoreDiscountScope", "RadrootsCoreDiscountThreshold", @@ -224,69 +270,173 @@ fn core_import_options( "RadrootsCoreQuantity", "RadrootsCoreQuantityPrice", "RadrootsCoreUnit", - "RadrootsCoreUnitDimension", ] { - if let Some(type_id) = core_type_id(registry, export_name) { - options = options.with_external_type(type_id, export_name, "@radroots/core-bindings"); - } + options = + with_checked_external_type(registry, options, export_name, CORE_BINDINGS_PACKAGE_NAME)?; } - options + Ok(options) } -fn core_type_id(registry: &Registry, rust_ident: &str) -> Option<TypeId> { - registry - .types_by_id - .iter() - .find_map(|(type_id, type_def)| match type_def { - TypeDef::Struct(def) if def.export_name == rust_ident => Some(*type_id), - TypeDef::Enum(def) if def.export_name == rust_ident => Some(*type_id), - _ => None, - }) +fn with_checked_external_type( + registry: &Registry, + options: DtoRegistryRenderOptions, + export_name: &str, + from: &str, +) -> Result<DtoRegistryRenderOptions, String> { + let type_id = registry + .type_id_by_export_name(export_name) + .map_err(|error| { + format!("failed to resolve external DTO type `{export_name}` from `{from}`: {error}") + })?; + Ok(options.with_external_type(type_id, export_name, from)) } -fn trade_import_options(mut options: DtoRegistryRenderOptions) -> DtoRegistryRenderOptions { - for export_name in [ - "RadrootsCoreCurrency", - "RadrootsCoreDecimal", - "RadrootsCoreDiscount", - "RadrootsCoreDiscountValue", - "RadrootsCoreMoney", - "RadrootsCoreQuantity", - "RadrootsCoreQuantityPrice", - "RadrootsCoreUnit", - ] { - options = - options.with_external_override(export_name, export_name, "@radroots/core-bindings"); +fn trade_import_options( + mut options: DtoRegistryRenderOptions, +) -> Result<DtoRegistryRenderOptions, String> { + let package_exports = generated_external_package_exports()?; + for override_target in TRADE_EXTERNAL_OVERRIDES { + validate_external_override_target(*override_target, &package_exports)?; + options = options.with_external_override( + override_target.target_type, + override_target.import_name, + override_target.from, + ); } - for export_name in [ - "RadrootsFarmRef", - "RadrootsListing", - "RadrootsListingAvailability", - "RadrootsListingBin", - "RadrootsListingDeliveryMethod", - "RadrootsListingImage", - "RadrootsListingProduct", - "RadrootsListingPublicLocation", - "RadrootsListingStatus", - "RadrootsNostrEventPtr", - "RadrootsOrderCancellation", - "RadrootsOrderDecision", - "RadrootsPlotRef", - "RadrootsResourceAreaRef", - "RadrootsOrderEconomicLine", - "RadrootsOrderItem", - "RadrootsOrderRequest", - "RadrootsOrderRevisionDecision", - "RadrootsOrderRevisionProposal", - "RadrootsTradeListingValidateRequest", - "RadrootsTradeListingValidateResult", - ] { - options = - options.with_external_override(export_name, export_name, "@radroots/events-bindings"); + Ok(options) +} + +fn generated_external_package_exports() -> Result<BTreeMap<&'static str, BTreeSet<String>>, String> +{ + Ok(BTreeMap::from([ + ( + CORE_BINDINGS_PACKAGE_KEY, + type_exports(core_types_module()?.body_ts()), + ), + ( + EVENTS_BINDINGS_PACKAGE_KEY, + type_exports(events_types_module()?.body_ts()), + ), + ])) +} + +fn validate_external_override_target( + override_target: DtoExternalOverride, + package_exports: &BTreeMap<&'static str, BTreeSet<String>>, +) -> Result<(), String> { + let exports = package_exports + .get(override_target.from_package_key) + .ok_or_else(|| { + format!( + "external DTO override `{}` references unknown package key `{}`", + override_target.target_type, override_target.from_package_key + ) + })?; + if exports.contains(override_target.import_name) { + return Ok(()); + } + Err(format!( + "external DTO override `{}` imports `{}` from `{}`, but package `{}` does not export it", + override_target.target_type, + override_target.import_name, + override_target.from, + override_target.from_package_key + )) +} + +fn validate_external_override_usage( + module: &DtoTypesModule, + overrides: &[DtoExternalOverride], +) -> Result<(), String> { + let imports = imported_type_inventory(module.imports_ts().unwrap_or_default()); + let package_exports = generated_external_package_exports()?; + for package_name in TRADE_REQUIRED_EXTERNAL_PACKAGE_IMPORTS { + if !imports.contains_key(*package_name) { + return Err(format!( + "expected generated DTO imports from `{package_name}` but none were emitted" + )); + } + } + + for override_target in overrides { + if type_exports(module.body_ts()).contains(override_target.target_type) { + return Err(format!( + "external DTO override `{}` from `{}` was emitted locally instead of imported", + override_target.target_type, override_target.from + )); + } + if imports + .get(override_target.from) + .is_some_and(|names| names.contains(override_target.import_name)) + { + validate_external_override_target(*override_target, &package_exports)?; + } + } + Ok(()) +} + +fn imported_type_inventory(imports_ts: &str) -> BTreeMap<String, BTreeSet<String>> { + let mut imports = BTreeMap::new(); + let mut pending_names: Option<Vec<String>> = None; + + for line in imports_ts.lines() { + let line = line.trim(); + if let Some(single) = line.strip_prefix("import type { ") { + if let Some((name, from)) = single.split_once(" } from ") { + insert_import(&mut imports, from, name); + } + } else if line == "import type {" { + pending_names = Some(Vec::new()); + } else if let Some(from) = line.strip_prefix("} from ") { + if let Some(names) = pending_names.take() { + for name in names { + insert_import(&mut imports, from, &name); + } + } + } else if let Some(names) = pending_names.as_mut() + && let Some(name) = line.strip_suffix(',') + { + names.push(name.to_owned()); + } + } + + imports +} + +fn insert_import(imports: &mut BTreeMap<String, BTreeSet<String>>, from: &str, name: &str) { + let from = from.trim_end_matches(';').trim_matches('"'); + imports + .entry(from.to_owned()) + .or_default() + .insert(name.trim().to_owned()); +} + +fn type_exports(types_ts: &str) -> BTreeSet<String> { + types_ts + .lines() + .filter_map(|line| line.strip_prefix("export type ")) + .filter_map(|rest| rest.split([' ', '<']).next()) + .map(str::to_owned) + .collect() +} + +const fn core_override(export_name: &'static str) -> DtoExternalOverride { + DtoExternalOverride { + target_type: export_name, + import_name: export_name, + from_package_key: CORE_BINDINGS_PACKAGE_KEY, + from: CORE_BINDINGS_PACKAGE_NAME, } +} - options +const fn events_override(export_name: &'static str) -> DtoExternalOverride { + DtoExternalOverride { + target_type: export_name, + import_name: export_name, + from_package_key: EVENTS_BINDINGS_PACKAGE_KEY, + from: EVENTS_BINDINGS_PACKAGE_NAME, + } } fn with_events_sdk_wrappers(body: &str) -> String { @@ -336,12 +486,18 @@ fn with_events_indexed_sdk_wrappers(body: &str) -> String { #[cfg(test)] mod tests { - use std::collections::BTreeSet; + use std::collections::{BTreeMap, BTreeSet}; + + use dto_bindgen_core::{Registry, RustTypeId, SourceSpan, StructDef, TypeDef}; use super::{ - DTO_PACKAGE_ROOTS, MANUAL_DESCRIPTOR_FAMILIES, SDK_LOCAL_WRAPPER_ALLOWANCES, - package_root_set, + CORE_BINDINGS_PACKAGE_KEY, CORE_BINDINGS_PACKAGE_NAME, DTO_PACKAGE_ROOTS, + DtoExternalOverride, MANUAL_DESCRIPTOR_FAMILIES, SDK_LOCAL_WRAPPER_ALLOWANCES, + events_override, imported_type_inventory, package_root_set, trade_import_options, + type_exports, validate_external_override_target, validate_external_override_usage, + with_checked_external_type, }; + use crate::dto_render::{DtoRegistryRenderOptions, DtoTypesModule}; const EVENTS_BINDINGS_TYPES_TS: &str = include_str!("../../../packages/events-bindings/src/generated/types.ts"); @@ -509,6 +665,7 @@ mod tests { "RadrootsTradeReviewQueueEntry", "RadrootsTradeReviewStatus", "RadrootsTradeSortDirection", + "RadrootsTradeWorkflowState", ]; #[test] @@ -569,6 +726,130 @@ mod tests { } #[test] + fn checked_external_type_lookup_rejects_missing_export() { + let registry = Registry::new(); + let error = with_checked_external_type( + &registry, + DtoRegistryRenderOptions::default(), + "MissingType", + CORE_BINDINGS_PACKAGE_NAME, + ) + .expect_err("missing export must fail"); + + assert_eq!( + error, + "failed to resolve external DTO type `MissingType` from `@radroots/core-bindings`: no DTO type exports `MissingType`" + ); + } + + #[test] + fn checked_external_type_lookup_rejects_duplicate_export() { + let mut registry = Registry::new(); + registry.register_type( + RustTypeId::new("sdk", "sdk", "FirstDuplicate"), + TypeDef::Struct(StructDef::new("FirstDuplicate", "DuplicateType", span())), + ); + registry.register_type( + RustTypeId::new("sdk", "sdk", "SecondDuplicate"), + TypeDef::Struct(StructDef::new("SecondDuplicate", "DuplicateType", span())), + ); + + let error = with_checked_external_type( + &registry, + DtoRegistryRenderOptions::default(), + "DuplicateType", + CORE_BINDINGS_PACKAGE_NAME, + ) + .expect_err("duplicate export must fail"); + + assert_eq!( + error, + "failed to resolve external DTO type `DuplicateType` from `@radroots/core-bindings`: DTO export name `DuplicateType` is ambiguous across 2 types" + ); + } + + #[test] + fn trade_external_override_targets_resolve_to_generated_exports() { + trade_import_options(DtoRegistryRenderOptions::default()) + .expect("trade external overrides validate"); + } + + #[test] + fn external_override_target_validation_rejects_missing_generated_export() { + let package_exports = BTreeMap::from([( + CORE_BINDINGS_PACKAGE_KEY, + BTreeSet::from(["ExistingType".to_owned()]), + )]); + let error = validate_external_override_target( + DtoExternalOverride { + target_type: "MissingType", + import_name: "MissingType", + from_package_key: CORE_BINDINGS_PACKAGE_KEY, + from: CORE_BINDINGS_PACKAGE_NAME, + }, + &package_exports, + ) + .expect_err("missing target package export must fail"); + + assert_eq!( + error, + "external DTO override `MissingType` imports `MissingType` from `@radroots/core-bindings`, but package `core` does not export it" + ); + } + + #[test] + fn external_override_usage_rejects_absent_required_package_import() { + let module = DtoTypesModule::new("", "export type RadrootsTradeListing = string;"); + let error = validate_external_override_usage(&module, &[]) + .expect_err("missing required package import must fail"); + + assert_eq!( + error, + "expected generated DTO imports from `@radroots/core-bindings` but none were emitted" + ); + } + + #[test] + fn external_override_usage_rejects_local_emission_for_imported_type() { + let module = DtoTypesModule::new( + "import type { RadrootsCoreDecimal } from \"@radroots/core-bindings\";\n\nimport type { RadrootsFarmRef } from \"@radroots/events-bindings\";\n\n", + "export type RadrootsFarmRef = { pubkey: string, d_tag: string, };", + ); + let error = + validate_external_override_usage(&module, &[events_override("RadrootsFarmRef")]) + .expect_err("local emission of imported type must fail"); + + assert_eq!( + error, + "external DTO override `RadrootsFarmRef` from `@radroots/events-bindings` was emitted locally instead of imported" + ); + } + + #[test] + fn generated_import_inventory_parses_single_and_multiline_imports() { + let imports = imported_type_inventory( + "import type { One } from \"@radroots/one\";\nimport type {\n Two,\n Three,\n} from \"@radroots/many\";\n\n", + ); + + assert_eq!( + imports.get("@radroots/one").expect("single import package"), + &BTreeSet::from(["One".to_owned()]) + ); + assert_eq!( + imports.get("@radroots/many").expect("multi import package"), + &BTreeSet::from(["Three".to_owned(), "Two".to_owned()]) + ); + } + + #[test] + fn generated_type_export_inventory_parses_type_aliases() { + assert_eq!( + type_exports("export type Alpha = string;\nexport type Beta<T> = T;\n"), + BTreeSet::from(["Alpha".to_owned(), "Beta".to_owned()]) + ); + } + + #[test] fn events_type_inventory_matches_current_package_surface() { let actual = type_inventory(EVENTS_BINDINGS_TYPES_TS); @@ -693,4 +974,8 @@ mod tests { .find(|line| line.starts_with(&format!("export type {name} = "))) .unwrap_or_else(|| panic!("missing type declaration for {name}")) } + + fn span() -> SourceSpan { + SourceSpan::new("tools/xtask/src/dto_roots.rs", 1, 1) + } }