Skip to content

Commit

Permalink
oapi: Add support of links (#900)
Browse files Browse the repository at this point in the history
* oapi: Add support of links

* cargo fmt
  • Loading branch information
chrislearn authored Sep 12, 2024
1 parent bbbabda commit 5851c4b
Show file tree
Hide file tree
Showing 33 changed files with 813 additions and 384 deletions.
4 changes: 2 additions & 2 deletions crates/oapi-macros/src/endpoint/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ pub(crate) struct EndpointAttr<'p> {

pub(crate) doc_comments: Option<Vec<String>>,
pub(crate) deprecated: Option<bool>,
pub(crate) description: Option<parse_utils::Value>,
pub(crate) summary: Option<parse_utils::Value>,
pub(crate) description: Option<parse_utils::LitStrOrExpr>,
pub(crate) summary: Option<parse_utils::LitStrOrExpr>,
}

impl Parse for EndpointAttr<'_> {
Expand Down
2 changes: 1 addition & 1 deletion crates/oapi-macros/src/feature/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ impl From<SkipBound> for Feature {
impl_get_name!(SkipBound = "skip_bound");

#[derive(Clone, Debug)]
pub(crate) struct Description(pub(crate) parse_utils::Value);
pub(crate) struct Description(pub(crate) parse_utils::LitStrOrExpr);
impl Parse for Description {
fn parse(input: ParseStream, _: Ident) -> syn::Result<Self>
where
Expand Down
2 changes: 2 additions & 0 deletions crates/oapi-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mod response;
mod schema;
mod schema_type;
mod security_requirement;
mod server;
mod shared;
mod type_tree;

Expand All @@ -39,6 +40,7 @@ pub(crate) use self::{
operation::Operation,
parameter::Parameter,
response::Response,
server::Server,
shared::*,
type_tree::TypeTree,
};
Expand Down
45 changes: 25 additions & 20 deletions crates/oapi-macros/src/operation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use quote::{quote, ToTokens};
use syn::{parenthesized, parse::Parse, token::Paren, Expr, ExprPath, Path, Token, Type};

use crate::endpoint::EndpointAttr;
use crate::parse_utils::LitStrOrExpr;
use crate::schema_type::SchemaType;
use crate::security_requirement::SecurityRequirementsAttr;
use crate::type_tree::{GenericType, TypeTree};
use crate::{parse_utils, Array, DiagResult, TryToTokens};
use crate::{Array, DiagResult, TryToTokens};

pub(crate) mod example;
pub(crate) mod request_body;
Expand Down Expand Up @@ -49,16 +50,20 @@ impl<'a> Operation<'a> {
(summary, trimmed)
});

let summary = attr.summary.as_ref().map(Summary::Value).or_else(|| {
split_comment
.as_ref()
.map(|(summary, _)| Summary::Str(summary))
});
let summary = attr
.summary
.as_ref()
.map(Summary::LitStrOrExpr)
.or_else(|| {
split_comment
.as_ref()
.map(|(summary, _)| Summary::Str(summary))
});

let description = attr
.description
.as_ref()
.map(Description::Value)
.map(Description::LitStrOrExpr)
.or_else(|| {
split_comment
.as_ref()
Expand Down Expand Up @@ -209,28 +214,28 @@ fn generate_register_schemas(oapi: &Ident, content: &PathType) -> Vec<TokenStrea

#[derive(Debug)]
enum Description<'a> {
Value(&'a parse_utils::Value),
LitStrOrExpr(&'a LitStrOrExpr),
Vec(&'a [String]),
}
impl<'a> Description<'a> {
fn is_empty(&self) -> bool {
match self {
Self::Value(value) => value.is_empty(),
Self::Vec(vec) => vec.iter().all(|s| s.is_empty()),
Self::LitStrOrExpr(value) => value.is_empty(),
Self::Vec(value) => value.iter().all(|s| s.is_empty()),
}
}
}

impl ToTokens for Description<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Self::Value(value) => {
Self::LitStrOrExpr(value) => {
if !value.is_empty() {
value.to_tokens(tokens)
}
}
Self::Vec(vec) => {
let description = vec.join("\n\n");
Self::Vec(value) => {
let description = value.join("\n\n");

if !description.is_empty() {
description.to_tokens(tokens)
Expand All @@ -242,29 +247,29 @@ impl ToTokens for Description<'_> {

#[derive(Debug)]
enum Summary<'a> {
Value(&'a parse_utils::Value),
LitStrOrExpr(&'a LitStrOrExpr),
Str(&'a str),
}
impl<'a> Summary<'a> {
pub(crate) fn is_empty(&self) -> bool {
match self {
Self::Value(value) => value.is_empty(),
Self::Str(str) => str.is_empty(),
Self::LitStrOrExpr(value) => value.is_empty(),
Self::Str(value) => value.is_empty(),
}
}
}

impl ToTokens for Summary<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Self::Value(value) => {
Self::LitStrOrExpr(value) => {
if !value.is_empty() {
value.to_tokens(tokens)
}
}
Self::Str(str) => {
if !str.is_empty() {
str.to_tokens(tokens)
Self::Str(value) => {
if !value.is_empty() {
value.to_tokens(tokens)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/oapi-macros/src/operation/request_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ use super::{PathType, PathTypeTree};
#[derive(Default, Debug)]
pub(crate) struct RequestBodyAttr<'r> {
pub(crate) content: Option<PathType<'r>>,
pub(crate) content_type: Option<parse_utils::Value>,
pub(crate) description: Option<parse_utils::Value>,
pub(crate) content_type: Option<parse_utils::LitStrOrExpr>,
pub(crate) description: Option<parse_utils::LitStrOrExpr>,
pub(crate) example: Option<AnyValue>,
pub(crate) examples: Option<Punctuated<Example, Token![,]>>,
}
Expand Down
22 changes: 11 additions & 11 deletions crates/oapi-macros/src/parse_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,40 @@ use syn::{
};

#[derive(Clone, Debug)]
pub(crate) enum Value {
pub(crate) enum LitStrOrExpr {
LitStr(LitStr),
Expr(Expr),
}

impl Value {
impl LitStrOrExpr {
pub(crate) fn is_empty(&self) -> bool {
matches!(self, Self::LitStr(s) if s.value().is_empty())
}
}

impl From<String> for Value {
impl From<String> for LitStrOrExpr {
fn from(value: String) -> Self {
Self::LitStr(LitStr::new(&value, proc_macro2::Span::call_site()))
}
}

impl Default for Value {
impl Default for LitStrOrExpr {
fn default() -> Self {
Self::LitStr(LitStr::new("", proc_macro2::Span::call_site()))
}
}

impl Parse for Value {
impl Parse for LitStrOrExpr {
fn parse(input: ParseStream) -> syn::Result<Self> {
if input.peek(LitStr) {
Ok::<Value, syn::Error>(Value::LitStr(input.parse::<LitStr>()?))
Ok::<LitStrOrExpr, syn::Error>(LitStrOrExpr::LitStr(input.parse::<LitStr>()?))
} else {
Ok(Value::Expr(input.parse::<Expr>()?))
Ok(LitStrOrExpr::Expr(input.parse::<Expr>()?))
}
}
}

impl ToTokens for Value {
impl ToTokens for LitStrOrExpr {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Self::LitStr(str) => str.to_tokens(tokens),
Expand All @@ -52,7 +52,7 @@ impl ToTokens for Value {
}
}

impl Display for Value {
impl Display for LitStrOrExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LitStr(str) => write!(f, "{str}", str = str.value()),
Expand All @@ -76,8 +76,8 @@ pub(crate) fn parse_next_lit_str(input: ParseStream) -> syn::Result<String> {
Ok(parse_next(input, || input.parse::<LitStr>())?.value())
}

pub(crate) fn parse_next_lit_str_or_expr(input: ParseStream) -> syn::Result<Value> {
parse_next(input, || Value::parse(input)).map_err(|error| {
pub(crate) fn parse_next_lit_str_or_expr(input: ParseStream) -> syn::Result<LitStrOrExpr> {
parse_next(input, || LitStrOrExpr::parse(input)).map_err(|error| {
syn::Error::new(
error.span(),
format!("expected literal string or expression argument: {error}"),
Expand Down
14 changes: 7 additions & 7 deletions crates/oapi-macros/src/response/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl<'u> UnnamedStructResponse<'u> {
.expect("`ToResponses` must have `#[salvo(response(...))]` attribute");
let description = {
let s = CommentAttributes::from_attributes(attributes).as_formatted_string();
parse_utils::Value::LitStr(LitStr::new(&s, Span::call_site()))
parse_utils::LitStrOrExpr::LitStr(LitStr::new(&s, Span::call_site()))
};
let status_code = mem::take(&mut derive_value.status_code);
Ok(Self(
Expand Down Expand Up @@ -303,7 +303,7 @@ impl NamedStructResponse<'_> {
.expect("`ToResponses` must have `#[salvo(response(...))]` attribute");
let description = {
let s = CommentAttributes::from_attributes(attributes).as_formatted_string();
parse_utils::Value::LitStr(LitStr::new(&s, Span::call_site()))
parse_utils::LitStrOrExpr::LitStr(LitStr::new(&s, Span::call_site()))
};
let status_code = mem::take(&mut derive_value.status_code);

Expand Down Expand Up @@ -353,7 +353,7 @@ impl UnitStructResponse<'_> {
let status_code = mem::take(&mut derive_value.status_code);
let description = {
let s = CommentAttributes::from_attributes(attributes).as_formatted_string();
parse_utils::Value::LitStr(LitStr::new(&s, Span::call_site()))
parse_utils::LitStrOrExpr::LitStr(LitStr::new(&s, Span::call_site()))
};

Ok(Self(
Expand Down Expand Up @@ -389,7 +389,7 @@ impl<'p> ToResponseNamedStructResponse<'p> {
let derive_value = DeriveToResponseValue::from_attributes(attributes)?;
let description = {
let s = CommentAttributes::from_attributes(attributes).as_formatted_string();
parse_utils::Value::LitStr(LitStr::new(&s, Span::call_site()))
parse_utils::LitStrOrExpr::LitStr(LitStr::new(&s, Span::call_site()))
};
let ty = Self::to_type(ident);

Expand Down Expand Up @@ -444,7 +444,7 @@ impl<'u> ToResponseUnnamedStructResponse<'u> {
let derive_value = DeriveToResponseValue::from_attributes(attributes)?;
let description = {
let s = CommentAttributes::from_attributes(attributes).as_formatted_string();
parse_utils::Value::LitStr(LitStr::new(&s, Span::call_site()))
parse_utils::LitStrOrExpr::LitStr(LitStr::new(&s, Span::call_site()))
};

let mut is_inline = false;
Expand Down Expand Up @@ -499,7 +499,7 @@ impl<'r> EnumResponse<'r> {
let ty = Self::to_type(ident);
let description = {
let s = CommentAttributes::from_attributes(attributes).as_formatted_string();
parse_utils::Value::LitStr(LitStr::new(&s, Span::call_site()))
parse_utils::LitStrOrExpr::LitStr(LitStr::new(&s, Span::call_site()))
};

let variants_content = variants
Expand Down Expand Up @@ -652,7 +652,7 @@ impl ToResponseUnitStructResponse<'_> {
let derive_value = DeriveToResponseValue::from_attributes(attributes)?;
let description = {
let s = CommentAttributes::from_attributes(attributes).as_formatted_string();
parse_utils::Value::LitStr(LitStr::new(&s, Span::call_site()))
parse_utils::LitStrOrExpr::LitStr(LitStr::new(&s, Span::call_site()))
};
let response_value: ResponseValue = ResponseValue::from(DeriveResponsesAttributes {
derive_value,
Expand Down
Loading

0 comments on commit 5851c4b

Please sign in to comment.