diff --git a/Cargo.lock b/Cargo.lock index 1d927ed..3ba1d33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,10 +150,19 @@ dependencies = [ ] [[package]] -name = "convert_case" -version = "0.4.0" +name = "console" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "regex", + "terminal_size", + "unicode-width", + "winapi", +] [[package]] name = "core-foundation" @@ -191,12 +200,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - [[package]] name = "digest" version = "0.8.1" @@ -304,6 +307,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.30" @@ -340,12 +349,13 @@ dependencies = [ [[package]] name = "expectorate" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804d601ea8a13ddbecf5ab4b6cf75b5d6d0539479c6fb2aea1596e352a5ee27e" +checksum = "5d9b457178b54cf0321a39fb6643ad7b9c705cf483ad4fb6d6092054e9ce839e" dependencies = [ - "difference", + "console", "newline-converter", + "similar", ] [[package]] @@ -537,6 +547,12 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1039,10 +1055,10 @@ dependencies = [ name = "progenitor-impl" version = "0.0.0" dependencies = [ - "convert_case", "dropshot", "expectorate", "getopts", + "heck", "http", "hyper", "indexmap", @@ -1412,6 +1428,12 @@ dependencies = [ "libc", ] +[[package]] +name = "similar" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" + [[package]] name = "slab" version = "0.4.5" @@ -1549,6 +1571,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -1761,7 +1793,7 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "typify" version = "0.0.6-dev" -source = "git+https://github.com/oxidecomputer/typify#8316b7d227eeec59d854279e947b1882ae2c635a" +source = "git+https://github.com/oxidecomputer/typify#4494446aac57ad0841f0d91ba0a9c1acca5de228" dependencies = [ "typify-impl", "typify-macro", @@ -1770,9 +1802,9 @@ dependencies = [ [[package]] name = "typify-impl" version = "0.0.6-dev" -source = "git+https://github.com/oxidecomputer/typify#8316b7d227eeec59d854279e947b1882ae2c635a" +source = "git+https://github.com/oxidecomputer/typify#4494446aac57ad0841f0d91ba0a9c1acca5de228" dependencies = [ - "convert_case", + "heck", "log", "proc-macro2", "quote", @@ -1787,7 +1819,7 @@ dependencies = [ [[package]] name = "typify-macro" version = "0.0.6-dev" -source = "git+https://github.com/oxidecomputer/typify#8316b7d227eeec59d854279e947b1882ae2c635a" +source = "git+https://github.com/oxidecomputer/typify#4494446aac57ad0841f0d91ba0a9c1acca5de228" dependencies = [ "proc-macro2", "quote", diff --git a/progenitor-impl/Cargo.toml b/progenitor-impl/Cargo.toml index cc0835c..60c1d91 100644 --- a/progenitor-impl/Cargo.toml +++ b/progenitor-impl/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/oxidecomputer/progenitor.git" description = "An OpenAPI client generator - core implementation" [dependencies] -convert_case = "0.4" +heck = "0.4.0" getopts = "0.2" indexmap = "1.7" openapiv3 = "1.0.0" diff --git a/progenitor-impl/src/method.rs b/progenitor-impl/src/method.rs index c57ee43..dd92745 100644 --- a/progenitor-impl/src/method.rs +++ b/progenitor-impl/src/method.rs @@ -5,13 +5,16 @@ use std::{ collections::{BTreeSet, HashMap}, }; -use convert_case::Case; use openapiv3::{Components, Response, StatusCode}; use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; use typify::TypeId; -use crate::{template::PathTemplate, util::sanitize, Error, Generator, Result}; +use crate::{ + template::PathTemplate, + util::{sanitize, Case}, + Error, Generator, Result, +}; use crate::{to_schema::ToSchema, util::ReferenceOrExt}; pub(crate) struct OperationMethod { diff --git a/progenitor-impl/src/to_schema.rs b/progenitor-impl/src/to_schema.rs index 81e4b85..15adb09 100644 --- a/progenitor-impl/src/to_schema.rs +++ b/progenitor-impl/src/to_schema.rs @@ -120,6 +120,7 @@ impl Convert for openapiv3::Schema { }; let metadata = Some(Box::new(metadata)).reduce(); + let extensions = extensions.into_iter().collect(); match &self.schema_kind { openapiv3::SchemaKind::Type(openapiv3::Type::String( @@ -144,7 +145,7 @@ impl Convert for openapiv3::Schema { pattern: pattern.clone(), })) .reduce(), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() }, openapiv3::SchemaKind::Type(openapiv3::Type::Number( @@ -188,7 +189,7 @@ impl Convert for openapiv3::Schema { }, )) .reduce(), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } @@ -236,7 +237,7 @@ impl Convert for openapiv3::Schema { }, )) .reduce(), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } @@ -265,7 +266,7 @@ impl Convert for openapiv3::Schema { property_names: None, })) .reduce(), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() }, @@ -295,7 +296,7 @@ impl Convert for openapiv3::Schema { contains: None, })) .reduce(), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() }, @@ -306,59 +307,63 @@ impl Convert for openapiv3::Schema { schemars::schema::InstanceType::Boolean, nullable, ), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } openapiv3::SchemaKind::OneOf { one_of } => { schemars::schema::SchemaObject { + metadata, subschemas: Some(Box::new( schemars::schema::SubschemaValidation { one_of: Some(one_of.convert()), ..Default::default() }, )), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } openapiv3::SchemaKind::AllOf { all_of } => { schemars::schema::SchemaObject { + metadata, subschemas: Some(Box::new( schemars::schema::SubschemaValidation { all_of: Some(all_of.convert()), ..Default::default() }, )), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } openapiv3::SchemaKind::AnyOf { any_of } => { schemars::schema::SchemaObject { + metadata, subschemas: Some(Box::new( schemars::schema::SubschemaValidation { any_of: Some(any_of.convert()), ..Default::default() }, )), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } openapiv3::SchemaKind::Not { not } => { schemars::schema::SchemaObject { + metadata, subschemas: Some(Box::new( schemars::schema::SubschemaValidation { not: Some(Box::new(not.convert())), ..Default::default() }, )), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } @@ -396,10 +401,11 @@ impl Convert for openapiv3::Schema { && all_of.is_empty() && any_of.is_empty() => { - let mut schema = - schemars::schema::Schema::Bool(true).into_object(); - schema.extensions = extensions.into_iter().collect(); - schema + schemars::schema::SchemaObject { + metadata, + extensions, + ..schemars::schema::Schema::Bool(true).into_object() + } } // A simple null value. @@ -441,7 +447,7 @@ impl Convert for openapiv3::Schema { instance_type: Some( schemars::schema::InstanceType::Null.into(), ), - extensions: extensions.into_iter().collect(), + extensions, ..Default::default() } } diff --git a/progenitor-impl/src/util.rs b/progenitor-impl/src/util.rs index 8804644..f4fe189 100644 --- a/progenitor-impl/src/util.rs +++ b/progenitor-impl/src/util.rs @@ -1,6 +1,5 @@ // Copyright 2022 Oxide Computer Company -use convert_case::{Case, Casing}; use indexmap::IndexMap; use openapiv3::{ Components, Parameter, ReferenceOr, RequestBody, Response, Schema, @@ -65,14 +64,30 @@ impl ComponentLookup for Schema { } } +pub(crate) enum Case { + Pascal, + Snake, +} + pub(crate) fn sanitize(input: &str, case: Case) -> String { - let out = input - .replace("'", "") - .replace(|c: char| !c.is_xid_continue(), "-") - .to_case(case); + use heck::{ToPascalCase, ToSnakeCase}; + let to_case = match case { + Case::Pascal => str::to_pascal_case, + Case::Snake => str::to_snake_case, + }; + // If every case was special then none of them would be. + let out = match input { + "+1" => "plus1".to_string(), + "-1" => "minus1".to_string(), + _ => to_case( + &input + .replace("'", "") + .replace(|c: char| !c.is_xid_continue(), "-"), + ), + }; let out = match out.chars().next() { - None => "x".to_case(case), + None => to_case("x"), Some(c) if c.is_xid_start() => out, Some(_) => format!("_{}", out), }; diff --git a/progenitor-impl/tests/output/nexus.out b/progenitor-impl/tests/output/nexus.out index 5fa1472..dbfa0cb 100644 --- a/progenitor-impl/tests/output/nexus.out +++ b/progenitor-impl/tests/output/nexus.out @@ -49,6 +49,7 @@ pub mod types { pub device_path: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, pub project_id: uuid::Uuid, pub size: ByteCount, @@ -66,6 +67,7 @@ pub mod types { pub struct DiskCreate { pub description: String, pub name: Name, + #[doc = "size of the Disk"] pub size: ByteCount, #[doc = "id for snapshot from which the Disk should be created, if any"] #[serde(default, skip_serializing_if = "Option::is_none")] @@ -88,6 +90,7 @@ pub mod types { pub next_page: Option, } + #[doc = "State of a Disk (primarily: attached or not)"] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "state", content = "instance")] pub enum DiskState { @@ -186,8 +189,11 @@ pub mod types { pub hostname: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "memory allocated for this Instance"] pub memory: ByteCount, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, + #[doc = "number of CPUs allocated for this Instance"] pub ncpus: InstanceCpuCount, #[doc = "id for the project containing this Instance"] pub project_id: uuid::Uuid, @@ -217,6 +223,7 @@ pub mod types { pub memory: ByteCount, pub name: Name, pub ncpus: InstanceCpuCount, + #[doc = "The network interfaces to be created for this instance."] #[serde(default, skip_serializing_if = "Option::is_none")] pub network_interfaces: Option, } @@ -227,6 +234,7 @@ pub mod types { pub dst_sled_uuid: uuid::Uuid, } + #[doc = "Describes an attachment of a `NetworkInterface` to an `Instance`, at the time the instance is created."] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", content = "params")] pub enum InstanceNetworkInterfaceAttachment { @@ -292,6 +300,7 @@ pub mod types { } } + #[doc = "An `IpNet` represents an IP network, either IPv4 or IPv6."] #[derive(Serialize, Deserialize, Debug, Clone)] pub enum IpNet { V4(Ipv4Net), @@ -400,7 +409,9 @@ pub mod types { pub instance_id: uuid::Uuid, #[doc = "The IP address assigned to this interface."] pub ip: String, + #[doc = "The MAC address assigned to this interface."] pub mac: MacAddr, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "The subnet to which the interface belongs."] pub subnet_id: uuid::Uuid, @@ -420,7 +431,9 @@ pub mod types { #[serde(default, skip_serializing_if = "Option::is_none")] pub ip: Option, pub name: Name, + #[doc = "The VPC Subnet in which to create the interface."] pub subnet_name: Name, + #[doc = "The VPC in which to create the interface."] pub vpc_name: Name, } @@ -441,6 +454,7 @@ pub mod types { pub description: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "timestamp when this resource was created"] pub time_created: chrono::DateTime, @@ -481,6 +495,7 @@ pub mod types { pub description: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, pub organization_id: uuid::Uuid, #[doc = "timestamp when this resource was created"] @@ -522,6 +537,7 @@ pub mod types { pub description: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "timestamp when this resource was created"] pub time_created: chrono::DateTime, @@ -566,6 +582,7 @@ pub mod types { pub next_page: Option, } + #[doc = "A `RouteDestination` is used to match traffic with a routing rule, on the destination of that traffic.\n\nWhen traffic is to be sent to a destination that is within a given `RouteDestination`, the corresponding [`RouterRoute`] applies, and traffic will be forward to the [`RouteTarget`] for that rule."] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", content = "value")] pub enum RouteDestination { @@ -579,6 +596,7 @@ pub mod types { Subnet(Name), } + #[doc = "A `RouteTarget` describes the possible locations that traffic matching a route destination can be sent."] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", content = "value")] pub enum RouteTarget { @@ -602,7 +620,9 @@ pub mod types { pub destination: RouteDestination, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "Describes the kind of router. Set at creation. `read-only`"] pub kind: RouterRouteKind, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "The VPC Router to which the route belongs."] pub router_id: uuid::Uuid, @@ -725,6 +745,7 @@ pub mod types { pub description: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, pub service_address: String, #[doc = "timestamp when this resource was created"] @@ -751,6 +772,7 @@ pub mod types { pub disk_id: uuid::Uuid, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, pub project_id: uuid::Uuid, pub size: ByteCount, @@ -764,6 +786,7 @@ pub mod types { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SnapshotCreate { pub description: String, + #[doc = "The name of the disk to be snapshotted"] pub disk: Name, pub name: Name, } @@ -814,6 +837,7 @@ pub mod types { pub description: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "timestamp when this resource was created"] pub time_created: chrono::DateTime, @@ -836,11 +860,13 @@ pub mod types { pub struct Vpc { #[doc = "human-readable free-form text about a resource"] pub description: String, + #[doc = "The name used for the VPC in DNS."] pub dns_name: Name, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, - #[serde(rename = "ipv6_prefix")] - pub ipv_6_prefix: Ipv6Net, + #[doc = "The unique local IPv6 address range for subnets in this VPC"] + pub ipv6_prefix: Ipv6Net, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "id for the project containing this VPC"] pub project_id: uuid::Uuid, @@ -857,28 +883,30 @@ pub mod types { pub struct VpcCreate { pub description: String, pub dns_name: Name, - #[serde( - rename = "ipv6_prefix", - default, - skip_serializing_if = "Option::is_none" - )] - pub ipv_6_prefix: Option, + #[doc = "The IPv6 prefix for this VPC.\n\nAll IPv6 subnets created from this VPC must be taken from this range, which sould be a Unique Local Address in the range `fd00::/48`. The default VPC Subnet will have the first `/64` range from this prefix."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ipv6_prefix: Option, pub name: Name, } #[doc = "A single rule in a VPC firewall"] #[derive(Serialize, Deserialize, Debug, Clone)] pub struct VpcFirewallRule { + #[doc = "whether traffic matching the rule should be allowed or dropped"] pub action: VpcFirewallRuleAction, #[doc = "human-readable free-form text about a resource"] pub description: String, + #[doc = "whether this rule is for incoming or outgoing traffic"] pub direction: VpcFirewallRuleDirection, + #[doc = "reductions on the scope of the rule"] pub filters: VpcFirewallRuleFilter, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "the relative priority of this rule"] pub priority: u16, + #[doc = "whether this rule is in effect"] pub status: VpcFirewallRuleStatus, #[doc = "list of sets of instances that the rule applies to"] pub targets: Vec, @@ -938,6 +966,7 @@ pub mod types { pub protocols: Option>, } + #[doc = "The `VpcFirewallRuleHostFilter` is used to filter traffic on the basis of its source or destination host."] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", content = "value")] pub enum VpcFirewallRuleHostFilter { @@ -991,6 +1020,7 @@ pub mod types { } } + #[doc = "A `VpcFirewallRuleTarget` is used to specify the set of [`Instance`]s to which a firewall rule applies."] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", content = "value")] pub enum VpcFirewallRuleTarget { @@ -1009,14 +1039,19 @@ pub mod types { #[doc = "A single rule in a VPC firewall"] #[derive(Serialize, Deserialize, Debug, Clone)] pub struct VpcFirewallRuleUpdate { + #[doc = "whether traffic matching the rule should be allowed or dropped"] pub action: VpcFirewallRuleAction, #[doc = "human-readable free-form text about a resource"] pub description: String, + #[doc = "whether this rule is for incoming or outgoing traffic"] pub direction: VpcFirewallRuleDirection, + #[doc = "reductions on the scope of the rule"] pub filters: VpcFirewallRuleFilter, + #[doc = "name of the rule, unique to this VPC"] pub name: Name, #[doc = "the relative priority of this rule"] pub priority: u16, + #[doc = "whether this rule is in effect"] pub status: VpcFirewallRuleStatus, #[doc = "list of sets of instances that the rule applies to"] pub targets: Vec, @@ -1052,6 +1087,7 @@ pub mod types { #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, pub kind: VpcRouterKind, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "timestamp when this resource was created"] pub time_created: chrono::DateTime, @@ -1111,10 +1147,11 @@ pub mod types { pub description: String, #[doc = "unique, immutable, system-controlled identifier for each resource"] pub id: uuid::Uuid, - #[serde(rename = "ipv4_block")] - pub ipv_4_block: Ipv4Net, - #[serde(rename = "ipv6_block")] - pub ipv_6_block: Ipv6Net, + #[doc = "The IPv4 subnet CIDR block."] + pub ipv4_block: Ipv4Net, + #[doc = "The IPv6 subnet CIDR block."] + pub ipv6_block: Ipv6Net, + #[doc = "unique, mutable, user-controlled identifier for each resource"] pub name: Name, #[doc = "timestamp when this resource was created"] pub time_created: chrono::DateTime, @@ -1128,14 +1165,11 @@ pub mod types { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct VpcSubnetCreate { pub description: String, - #[serde(rename = "ipv4_block")] - pub ipv_4_block: Ipv4Net, - #[serde( - rename = "ipv6_block", - default, - skip_serializing_if = "Option::is_none" - )] - pub ipv_6_block: Option, + #[doc = "The IPv4 address range for this subnet.\n\nIt must be allocated from an RFC 1918 private address range, and must not overlap with any other existing subnet in the VPC."] + pub ipv4_block: Ipv4Net, + #[doc = "The IPv6 address range for this subnet.\n\nIt must be allocated from the RFC 4193 Unique Local Address range, with the prefix equal to the parent VPC's prefix. A random `/64` block will be assigned if one is not provided. It must not overlap with any existing subnet in the VPC."] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ipv6_block: Option, pub name: Name, } @@ -1154,18 +1188,10 @@ pub mod types { pub struct VpcSubnetUpdate { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, - #[serde( - rename = "ipv4_block", - default, - skip_serializing_if = "Option::is_none" - )] - pub ipv_4_block: Option, - #[serde( - rename = "ipv6_block", - default, - skip_serializing_if = "Option::is_none" - )] - pub ipv_6_block: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ipv4_block: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ipv6_block: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub name: Option, } diff --git a/progenitor/src/main.rs b/progenitor/src/main.rs index a291638..de84a01 100644 --- a/progenitor/src/main.rs +++ b/progenitor/src/main.rs @@ -166,10 +166,6 @@ where bail!("security not presently supported"); } - if !api.tags.is_empty() { - bail!("tags not presently supported"); - } - let mut opids = HashSet::new(); for p in api.paths.paths.iter() { match p.1 {