Skip to content

Openapi: adding more info in x-state, adding x-state info to fields and params #4431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions compiler-rs/clients_schema_to_openapi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ pub mod cli;

use indexmap::IndexMap;

use clients_schema::{Availabilities, Flavor, IndexedModel, Stability, Visibility};
use clients_schema::{Availabilities, Availability, Flavor, IndexedModel, Stability, Visibility};
use openapiv3::{Components, OpenAPI};
use serde_json::Value;
use clients_schema::transform::ExpandConfig;
use crate::components::TypesAndComponents;

Expand Down Expand Up @@ -103,7 +104,7 @@ pub fn convert_expanded_schema(model: &IndexedModel, config: &Configuration) ->
continue;
}
}
paths::add_endpoint(endpoint, &mut tac, &mut openapi.paths)?;
paths::add_endpoint(endpoint, &mut tac, &mut openapi.paths, &config.flavor)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config is part of tac, I added it in #4313. This effectively makes TypesAndComponents more than types and components. I'll open a PR to rename it to something more "kitchensink-esque" like Context.

}

// // Sort maps to ensure output stability
Expand Down Expand Up @@ -149,30 +150,37 @@ fn info(model: &IndexedModel) -> openapiv3::Info {
}
}

pub fn availability_as_extensions(availabilities: &Option<Availabilities>) -> IndexMap<String, serde_json::Value> {
pub fn availability_as_extensions(availabilities: &Option<Availabilities>, flavor: &Option<Flavor>) -> IndexMap<String, serde_json::Value> {
let mut result = IndexMap::new();
convert_availabilities(availabilities, flavor, &mut result);
result
}

pub fn convert_availabilities(availabilities: &Option<Availabilities>, flavor: &Option<Flavor>, result: &mut IndexMap<String, Value>) {
if let Some(avails) = availabilities {
// We may have several availabilities, but since generally exists only on stateful (stack)
for (_, availability) in avails {
if let Some(stability) = &availability.stability {
match stability {
if let Some(flav) = flavor {
if let Some(availability) = avails.get(flav) {
let Availability {since,stability,..} = &availability;
let stab = stability.clone().unwrap_or(Stability::Stable);
let mut since_str = "".to_string();
if let Some(since) = since {
since_str = "; Added in ".to_string() + since;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The + operator on String is rarely used in Rust. Prefer the more compact and more efficient since_str = format!("; Added in {since}");

}
match stab {
Stability::Beta => {
result.insert("x-beta".to_string(), serde_json::Value::Bool(true));
let beta_since = "Beta".to_string() + &since_str;
result.insert("x-state".to_string(), Value::String(beta_since));
}
Stability::Experimental => {
result.insert("x-state".to_string(), serde_json::Value::String("Technical preview".to_string()));
let exp_since = "Technical preview".to_string() + &since_str;
result.insert("x-state".to_string(), Value::String(exp_since));
}
Stability::Stable => {
if let Some(since) = &availability.since {
let stable_since = "Added in ".to_string() + since;
result.insert("x-state".to_string(), serde_json::Value::String(stable_since));
}
let stable_since = "Generally available".to_string() + &since_str;
result.insert("x-state".to_string(), Value::String(stable_since));
}
}
}
}
}

result
}
14 changes: 10 additions & 4 deletions compiler-rs/clients_schema_to_openapi/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,26 @@ use std::collections::HashMap;
use std::fmt::Write;

use anyhow::{anyhow, bail};
use clients_schema::Property;
use clients_schema::{Flavor, Property};
use indexmap::IndexMap;
use indexmap::indexmap;
use icu_segmenter::SentenceSegmenter;
use openapiv3::{
MediaType, Parameter, ParameterData, ParameterSchemaOrContent, PathItem, PathStyle, Paths, QueryStyle, ReferenceOr,
RequestBody, Response, Responses, StatusCode, Example
};
use serde_json::Value;
use clients_schema::SchemaExample;

use crate::components::TypesAndComponents;
use crate::convert_availabilities;

/// Add an endpoint to the OpenAPI schema. This will result in the addition of a number of elements to the
/// openapi schema's `paths` and `components` sections.
pub fn add_endpoint(
endpoint: &clients_schema::Endpoint,
tac: &mut TypesAndComponents,
out: &mut Paths,
flavor: &Option<Flavor>
) -> anyhow::Result<()> {
if endpoint.request.is_none() {
// tracing::warn!("Endpoint {} is missing a request -- ignored", &endpoint.name);
Expand All @@ -60,6 +62,8 @@ pub fn add_endpoint(
let request = tac.model.get_request(endpoint.request.as_ref().unwrap())?;

fn parameter_data(prop: &Property, in_path: bool, tac: &mut TypesAndComponents) -> anyhow::Result<ParameterData> {
let mut extensions: IndexMap<String,Value> = Default::default();
convert_availabilities(&prop.availability, &tac.config.flavor, &mut extensions);
Ok(ParameterData {
name: prop.name.clone(),
description: tac.property_description(prop)?,
Expand Down Expand Up @@ -252,7 +256,7 @@ pub fn add_endpoint(
let sum_desc = split_summary_desc(&endpoint.description);

// add the x-state extension for availability
let mut extensions = crate::availability_as_extensions(&endpoint.availability);
let mut extensions = crate::availability_as_extensions(&endpoint.availability, flavor);

// add the x-codeSamples extension
let mut code_samples = vec![];
Expand Down Expand Up @@ -286,6 +290,8 @@ pub fn add_endpoint(
if !code_samples.is_empty() {
extensions.insert("x-codeSamples".to_string(), serde_json::json!(code_samples));
}
let mut ext_availability = crate::availability_as_extensions(&endpoint.availability, flavor);
extensions.append(&mut ext_availability);

// Create the operation, it will be repeated if we have several methods
let operation = openapiv3::Operation {
Expand All @@ -310,7 +316,7 @@ pub fn add_endpoint(
deprecated: endpoint.deprecation.is_some(),
security: None,
servers: vec![],
extensions,
extensions
};


Expand Down
2 changes: 1 addition & 1 deletion compiler-rs/clients_schema_to_openapi/src/schemas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ impl<'a> TypesAndComponents<'a> {
data.external_docs = self.convert_external_docs(prop);
data.deprecated = prop.deprecation.is_some();
data.description = self.property_description(prop)?;
data.extensions = crate::availability_as_extensions(&prop.availability);
data.extensions = crate::availability_as_extensions(&prop.availability, &self.config.flavor);
// TODO: prop.aliases as extensions
// TODO: prop.server_default as extension
// TODO: prop.doc_id as extension (new representation of since and stability)
Expand Down
Binary file modified compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm
Binary file not shown.
Loading