Infer graphql "deprecation" from #[deprecated(note = "...")] in derive (and macros) (#269)
* Update object/iface macro with doc/deprecated attrs for fields * Use the note from `#[deprecated]` by default in derived GraphQLType * Update to support multiline raw-docstring format * Support bare deprecated attribute * Update arguments to support #[doc] for parity with previous ` as ` syntax
This commit is contained in:
parent
f61fdb2063
commit
0f2a654471
13 changed files with 804 additions and 49 deletions
|
@ -14,3 +14,73 @@
|
|||
generic code. To retain the current behaviour use `DefaultScalarValue` as scalar value type
|
||||
|
||||
[#251](https://github.com/graphql-rust/juniper/pull/251)
|
||||
|
||||
- The `GraphQLObject` and `GraphQLEnum` derives will mark graphql fields as
|
||||
`@deprecated` when struct fields or enum variants are marked with the
|
||||
builtin `#[deprecated]` attribute.
|
||||
|
||||
The deprecation reason can be set using the `note = ...` meta item
|
||||
(e.g. `#[deprecated(note = "Replaced by betterField")]`).
|
||||
The `since` attribute is ignored.
|
||||
|
||||
[#269](https://github.com/graphql-rust/juniper/pull/269)
|
||||
|
||||
|
||||
- There is an alternative syntax for setting a field's _description_ and
|
||||
_deprecation reason_ in the `graphql_object!` and `graphql_interface!` macros.
|
||||
|
||||
To __deprecate__ a graphql field:
|
||||
```rust
|
||||
// Original syntax for setting deprecation reason
|
||||
field deprecated "Reason" my_field() -> { ... }
|
||||
|
||||
// New alternative syntax for deprecation reason.
|
||||
#[deprecated(note = "Reason")]
|
||||
field my_field() -> { ... }
|
||||
|
||||
// You can now also deprecate without a reason.
|
||||
#[deprecated]
|
||||
field my_field() -> { ... }
|
||||
```
|
||||
|
||||
To set the __description__ of a graphql field:
|
||||
```rust
|
||||
// Original syntax for field descriptions
|
||||
field my_field() as "Description" -> { ... }
|
||||
|
||||
// Original syntax for argument descriptions
|
||||
field my_field(
|
||||
floops: i32 as "The number of starfish to be returned. \
|
||||
Can't be more than 100.",
|
||||
) -> {
|
||||
...
|
||||
}
|
||||
|
||||
// New alternative syntax for field descriptions
|
||||
#[doc = "Description"]
|
||||
field my_field() -> { ... }
|
||||
|
||||
// New alternative syntax for argument descriptions
|
||||
field my_field(
|
||||
#[doc = "The number of starfish to be returned. \
|
||||
Can't be more than 100."]
|
||||
arg: i32,
|
||||
) -> {
|
||||
...
|
||||
}
|
||||
|
||||
// You can also use raw strings and const &'static str.
|
||||
//
|
||||
// Multiple docstrings will be collapsed into a single
|
||||
// description separated by newlines.
|
||||
#[doc = r#"
|
||||
This is my field.
|
||||
|
||||
Make sure not to flitz the bitlet.
|
||||
Flitzing without a bitlet has undefined behaviour.
|
||||
"]
|
||||
#[doc = my_consts::ADDED_IN_VERSION_XYZ]
|
||||
field my_field() -> { ... }
|
||||
```
|
||||
|
||||
[#269](https://github.com/graphql-rust/juniper/pull/269)
|
||||
|
|
|
@ -15,8 +15,8 @@ use value::Value;
|
|||
use GraphQLError;
|
||||
|
||||
use schema::meta::{
|
||||
Argument, EnumMeta, EnumValue, Field, InputObjectMeta, InterfaceMeta, ListMeta, MetaType,
|
||||
NullableMeta, ObjectMeta, PlaceholderMeta, ScalarMeta, UnionMeta,
|
||||
Argument, DeprecationStatus, EnumMeta, EnumValue, Field, InputObjectMeta, InterfaceMeta,
|
||||
ListMeta, MetaType, NullableMeta, ObjectMeta, PlaceholderMeta, ScalarMeta, UnionMeta,
|
||||
};
|
||||
use schema::model::{RootNode, SchemaType, TypeType};
|
||||
|
||||
|
@ -729,7 +729,7 @@ where
|
|||
description: None,
|
||||
arguments: None,
|
||||
field_type: self.get_type::<T>(info),
|
||||
deprecation_reason: None,
|
||||
deprecation_status: DeprecationStatus::Current,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -748,7 +748,7 @@ where
|
|||
description: None,
|
||||
arguments: None,
|
||||
field_type: self.get_type::<I>(info),
|
||||
deprecation_reason: None,
|
||||
deprecation_status: DeprecationStatus::Current,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -398,7 +398,76 @@ macro_rules! __juniper_parse_field_list {
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
(
|
||||
success_callback = $success_callback: ident,
|
||||
additional_parser = {$($additional:tt)*},
|
||||
meta = {$($meta:tt)*},
|
||||
items = [$({$($items: tt)*},)*],
|
||||
rest = $(#[doc = $desc: tt])*
|
||||
#[deprecated $(( $(since = $since: tt,)* note = $reason: tt ))* ]
|
||||
field $name: ident (
|
||||
$(&$executor: tt)* $(,)*
|
||||
$($(#[doc = $arg_desc: expr])* $arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty),* $(,)*
|
||||
) -> $return_ty: ty $body: block
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
__juniper_parse_field_list!(
|
||||
success_callback = $success_callback,
|
||||
additional_parser = {$($additional)*},
|
||||
meta = {$($meta)*},
|
||||
items = [$({$($items)*},)* {
|
||||
name = $name,
|
||||
body = $body,
|
||||
return_ty = $return_ty,
|
||||
args = [
|
||||
$({
|
||||
arg_name = $arg_name,
|
||||
arg_ty = $arg_ty,
|
||||
$(arg_default = $arg_default,)*
|
||||
$(arg_docstring = $arg_desc,)*
|
||||
},)*
|
||||
],
|
||||
$(docstring = $desc,)*
|
||||
deprecated = None$(.unwrap_or(Some($reason)))*,
|
||||
$(executor_var = $executor,)*
|
||||
},],
|
||||
rest = $($rest)*
|
||||
);
|
||||
};
|
||||
(
|
||||
success_callback = $success_callback: ident,
|
||||
additional_parser = {$($additional:tt)*},
|
||||
meta = {$($meta:tt)*},
|
||||
items = [$({$($items: tt)*},)*],
|
||||
rest = $(#[doc = $desc: tt])*
|
||||
field $name: ident (
|
||||
$(&$executor: ident)* $(,)*
|
||||
$($(#[doc = $arg_desc: expr])* $arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty),* $(,)*
|
||||
) -> $return_ty: ty $body: block
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
__juniper_parse_field_list!(
|
||||
success_callback = $success_callback,
|
||||
additional_parser = {$($additional)*},
|
||||
meta = {$($meta)*},
|
||||
items = [$({$($items)*},)* {
|
||||
name = $name,
|
||||
body = $body,
|
||||
return_ty = $return_ty,
|
||||
args = [
|
||||
$({
|
||||
arg_name = $arg_name,
|
||||
arg_ty = $arg_ty,
|
||||
$(arg_default = $arg_default,)*
|
||||
$(arg_docstring = $arg_desc,)*
|
||||
},)*
|
||||
],
|
||||
$(docstring = $desc,)*
|
||||
$(executor_var = $executor,)*
|
||||
},],
|
||||
rest = $($rest)*
|
||||
);
|
||||
};
|
||||
(
|
||||
success_callback = $success_callback: ident,
|
||||
additional_parser = {$($additional:tt)*},
|
||||
|
@ -406,7 +475,7 @@ macro_rules! __juniper_parse_field_list {
|
|||
items = [$({$($items: tt)*},)*],
|
||||
rest = field deprecated $reason:tt $name: ident (
|
||||
$(&$executor: tt)* $(,)*
|
||||
$($arg_name:ident $(= $default_value: tt)* : $arg_ty: ty $(as $arg_des: expr)*),* $(,)*
|
||||
$($arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty $(as $arg_desc: expr)*),* $(,)*
|
||||
) -> $return_ty: ty $(as $desc: tt)* $body: block
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
|
@ -422,12 +491,12 @@ macro_rules! __juniper_parse_field_list {
|
|||
$({
|
||||
arg_name = $arg_name,
|
||||
arg_ty = $arg_ty,
|
||||
$(arg_default = $arg_default,)*
|
||||
$(arg_description = $arg_desc,)*
|
||||
$(arg_default = $default_value,)*
|
||||
},)*
|
||||
],
|
||||
$(decs = $desc,)*
|
||||
deprecated = $reason,
|
||||
deprecated = Some($reason),
|
||||
$(executor_var = $executor,)*
|
||||
},],
|
||||
rest = $($rest)*
|
||||
|
@ -440,7 +509,7 @@ macro_rules! __juniper_parse_field_list {
|
|||
items = [$({$($items: tt)*},)*],
|
||||
rest = field $name: ident (
|
||||
$(&$executor: ident)* $(,)*
|
||||
$($arg_name:ident $(= $default_value: tt)* : $arg_ty: ty $(as $arg_desc: expr)*),* $(,)*
|
||||
$($arg_name:ident $(= $arg_default: tt)* : $arg_ty: ty $(as $arg_desc: expr)*),* $(,)*
|
||||
) -> $return_ty: ty $(as $desc: tt)* $body: block
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
|
@ -456,8 +525,8 @@ macro_rules! __juniper_parse_field_list {
|
|||
$({
|
||||
arg_name = $arg_name,
|
||||
arg_ty = $arg_ty,
|
||||
$(arg_default = $arg_default,)*
|
||||
$(arg_description = $arg_desc,)*
|
||||
$(arg_default = $default_value,)*
|
||||
},)*
|
||||
],
|
||||
$(decs = $desc,)*
|
||||
|
@ -601,12 +670,14 @@ macro_rules! __juniper_create_arg {
|
|||
arg_ty = $arg_ty: ty,
|
||||
arg_name = $arg_name: ident,
|
||||
$(description = $arg_description: expr,)*
|
||||
$(docstring = $arg_docstring: expr,)*
|
||||
) => {
|
||||
$reg.arg::<$arg_ty>(
|
||||
&$crate::to_camel_case(stringify!($arg_name)),
|
||||
$info,
|
||||
)
|
||||
$(.description($arg_description))*
|
||||
$(.push_docstring($arg_docstring))*
|
||||
};
|
||||
|
||||
(
|
||||
|
@ -614,8 +685,9 @@ macro_rules! __juniper_create_arg {
|
|||
info = $info: ident,
|
||||
arg_ty = $arg_ty: ty,
|
||||
arg_name = $arg_name: ident,
|
||||
$(description = $arg_description: expr,)*
|
||||
default = $arg_default: expr,
|
||||
$(description = $arg_description: expr,)*
|
||||
$(docstring = $arg_docstring: expr,)*
|
||||
) => {
|
||||
$reg.arg_with_default::<$arg_ty>(
|
||||
&$crate::to_camel_case(stringify!($arg_name)),
|
||||
|
@ -623,5 +695,6 @@ macro_rules! __juniper_create_arg {
|
|||
$info,
|
||||
)
|
||||
$(.description($arg_description))*
|
||||
$(.push_docstring($arg_docstring))*
|
||||
};
|
||||
}
|
||||
|
|
|
@ -117,10 +117,12 @@ macro_rules! graphql_interface {
|
|||
args = [$({
|
||||
arg_name = $arg_name : ident,
|
||||
arg_ty = $arg_ty: ty,
|
||||
$(arg_description = $arg_description: expr,)*
|
||||
$(arg_default = $arg_default: expr,)*
|
||||
$(arg_description = $arg_description: expr,)*
|
||||
$(arg_docstring = $arg_docstring: expr,)*
|
||||
},)*],
|
||||
$(decs = $fn_description: expr,)*
|
||||
$(docstring = $docstring: expr,)*
|
||||
$(deprecated = $deprecated: expr,)*
|
||||
$(executor_var = $executor: ident,)*
|
||||
},)*],
|
||||
|
@ -151,6 +153,7 @@ macro_rules! graphql_interface {
|
|||
info
|
||||
)
|
||||
$(.description($fn_description))*
|
||||
$(.push_docstring($docstring))*
|
||||
$(.deprecated($deprecated))*
|
||||
$(.argument(
|
||||
__juniper_create_arg!(
|
||||
|
@ -158,8 +161,9 @@ macro_rules! graphql_interface {
|
|||
info = info,
|
||||
arg_ty = $arg_ty,
|
||||
arg_name = $arg_name,
|
||||
$(description = $arg_description,)*
|
||||
$(default = $arg_default,)*
|
||||
$(description = $arg_description,)*
|
||||
$(docstring = $arg_docstring,)*
|
||||
)
|
||||
))*,
|
||||
)*];
|
||||
|
|
|
@ -63,6 +63,45 @@ graphql_object!(User: () |&self| {
|
|||
# fn main() { }
|
||||
```
|
||||
|
||||
**Alternatively,** descriptions can be added with the builtin `doc` attribute.
|
||||
Consecutive `#[doc = "..."]` attributes will be collapsed into a single description
|
||||
where the docstrings are separated by newlines.
|
||||
|
||||
```rust
|
||||
# #[macro_use] extern crate juniper;
|
||||
struct User { id: String, name: String, group_ids: Vec<String> }
|
||||
|
||||
graphql_object!(User: () |&self| {
|
||||
description: "A user in the database"
|
||||
|
||||
#[doc = "The user's unique identifier"]
|
||||
field id() -> &String {
|
||||
&self.id
|
||||
}
|
||||
|
||||
#[doc = "The user's name"]
|
||||
field name() -> &String {
|
||||
&self.name
|
||||
}
|
||||
|
||||
#[doc = r#"
|
||||
Test if a user is member of a group.
|
||||
|
||||
This may return a flitzbit if the floop is twizled.
|
||||
Make sure not to rumblejumble the cog-rotater.
|
||||
"#]
|
||||
#[doc = "Added in vX.Y.44"]
|
||||
field member_of_group(
|
||||
#[doc = "The group id you want to test membership against"]
|
||||
group_id: String,
|
||||
) -> bool {
|
||||
self.group_ids.iter().any(|gid| gid == &group_id)
|
||||
}
|
||||
});
|
||||
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
## Generics and lifetimes
|
||||
|
||||
You can expose generic or pointer types by prefixing the type with the necessary
|
||||
|
@ -232,6 +271,24 @@ Defines a field on the object. The name is converted to camel case, e.g.
|
|||
`user_name` is exposed as `userName`. The `as "Field description"` adds the
|
||||
string as documentation on the field.
|
||||
|
||||
A field's description and deprecation can also be set using the
|
||||
builtin `doc` and `deprecated` attributes.
|
||||
|
||||
```text
|
||||
#[doc = "Field description"]
|
||||
field name(args...) -> Type { }
|
||||
|
||||
#[deprecated] // no reason required
|
||||
field name(args...) -> Type { }
|
||||
|
||||
#[deprecated(note = "Reason")]
|
||||
field name(args...) -> Type { }
|
||||
|
||||
#[doc = "Field description"]
|
||||
#[deprecated(note = "Reason")] // deprecated must come after doc
|
||||
field deprecated "Reason" name(args...) -> Type { }
|
||||
```
|
||||
|
||||
### Field arguments
|
||||
|
||||
```text
|
||||
|
@ -269,6 +326,13 @@ arg_name = (Point { x: 1, y: 2 }): Point
|
|||
arg_name = ("default".to_owned()): String
|
||||
```
|
||||
|
||||
A description can also be provided using the builtin `doc` attribute.
|
||||
|
||||
```text
|
||||
#[doc = "Argument description"]
|
||||
arg_name: ArgType
|
||||
```
|
||||
|
||||
[1]: struct.Executor.html
|
||||
|
||||
*/
|
||||
|
@ -295,10 +359,12 @@ macro_rules! graphql_object {
|
|||
args = [$({
|
||||
arg_name = $arg_name : ident,
|
||||
arg_ty = $arg_ty: ty,
|
||||
$(arg_description = $arg_description: expr,)*
|
||||
$(arg_default = $arg_default: expr,)*
|
||||
$(arg_description = $arg_description: expr,)*
|
||||
$(arg_docstring = $arg_docstring: expr,)*
|
||||
},)*],
|
||||
$(decs = $fn_description: expr,)*
|
||||
$(docstring = $docstring: expr,)*
|
||||
$(deprecated = $deprecated: expr,)*
|
||||
$(executor_var = $executor: ident,)*
|
||||
},)*],
|
||||
|
@ -325,6 +391,7 @@ macro_rules! graphql_object {
|
|||
info
|
||||
)
|
||||
$(.description($fn_description))*
|
||||
$(.push_docstring($docstring))*
|
||||
$(.deprecated($deprecated))*
|
||||
$(.argument(
|
||||
__juniper_create_arg!(
|
||||
|
@ -332,8 +399,9 @@ macro_rules! graphql_object {
|
|||
info = info,
|
||||
arg_ty = $arg_ty,
|
||||
arg_name = $arg_name,
|
||||
$(description = $arg_description,)*
|
||||
$(default = $arg_default,)*
|
||||
$(description = $arg_description,)*
|
||||
$(docstring = $arg_docstring,)*
|
||||
)
|
||||
))*,
|
||||
)*];
|
||||
|
|
|
@ -49,6 +49,13 @@ graphql_object!(Root: () |&self| {
|
|||
arg2: i32 as "The second arg",
|
||||
) -> i32 { 0 }
|
||||
|
||||
field attr_arg_descr(#[doc = "The arg"] arg: i32) -> i32 { 0 }
|
||||
field attr_arg_descr_collapse(
|
||||
#[doc = "The arg"]
|
||||
#[doc = "and more details"]
|
||||
arg: i32,
|
||||
) -> i32 { 0 }
|
||||
|
||||
field arg_with_default(arg = 123: i32) -> i32 { 0 }
|
||||
field multi_args_with_default(
|
||||
arg1 = 123: i32,
|
||||
|
@ -499,6 +506,72 @@ fn introspect_field_multi_args_descr_trailing_comma() {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_field_attr_arg_descr() {
|
||||
run_args_info_query("attrArgDescr", |args| {
|
||||
assert_eq!(args.len(), 1);
|
||||
|
||||
assert!(
|
||||
args.contains(&Value::object(
|
||||
vec![
|
||||
("name", Value::scalar("arg")),
|
||||
("description", Value::scalar("The arg")),
|
||||
("defaultValue", Value::null()),
|
||||
(
|
||||
"type",
|
||||
Value::object(
|
||||
vec![
|
||||
("name", Value::null()),
|
||||
(
|
||||
"ofType",
|
||||
Value::object(
|
||||
vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
||||
),
|
||||
),
|
||||
].into_iter()
|
||||
.collect(),
|
||||
),
|
||||
),
|
||||
].into_iter()
|
||||
.collect(),
|
||||
))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_field_attr_arg_descr_collapse() {
|
||||
run_args_info_query("attrArgDescrCollapse", |args| {
|
||||
assert_eq!(args.len(), 1);
|
||||
|
||||
assert!(
|
||||
args.contains(&Value::object(
|
||||
vec![
|
||||
("name", Value::scalar("arg")),
|
||||
("description", Value::scalar("The arg\nand more details")),
|
||||
("defaultValue", Value::null()),
|
||||
(
|
||||
"type",
|
||||
Value::object(
|
||||
vec![
|
||||
("name", Value::null()),
|
||||
(
|
||||
"ofType",
|
||||
Value::object(
|
||||
vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
||||
),
|
||||
),
|
||||
].into_iter()
|
||||
.collect(),
|
||||
),
|
||||
),
|
||||
].into_iter()
|
||||
.collect(),
|
||||
))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_field_arg_with_default() {
|
||||
run_args_info_query("argWithDefault", |args| {
|
||||
|
|
|
@ -31,6 +31,31 @@ graphql_object!(Root: () |&self| {
|
|||
field deprecated "Deprecation reason"
|
||||
deprecated_descr() -> i32 as "Field description" { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
field attr_description() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
#[doc = "with `collapse_docs` behavior"] // https://doc.rust-lang.org/rustdoc/the-doc-attribute.html
|
||||
field attr_description_collapse() -> i32 { 0 }
|
||||
|
||||
#[doc = r#"
|
||||
Get the i32 representation of 0.
|
||||
|
||||
- This comment is longer.
|
||||
- These two lines are rendered as bullets by GraphiQL.
|
||||
"#]
|
||||
field attr_description_long() -> i32 { 0 }
|
||||
|
||||
#[deprecated]
|
||||
field attr_deprecated() -> i32 { 0 }
|
||||
|
||||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_reason() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_descr() -> i32 { 0 }
|
||||
|
||||
field with_field_result() -> FieldResult<i32> { Ok(0) }
|
||||
|
||||
field with_return() -> i32 { return 0; }
|
||||
|
@ -51,6 +76,31 @@ graphql_interface!(Interface: () |&self| {
|
|||
field deprecated "Deprecation reason"
|
||||
deprecated_descr() -> i32 as "Field description" { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
field attr_description() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
#[doc = "with `collapse_docs` behavior"] // https://doc.rust-lang.org/rustdoc/the-doc-attribute.html
|
||||
field attr_description_collapse() -> i32 { 0 }
|
||||
|
||||
#[doc = r#"
|
||||
Get the i32 representation of 0.
|
||||
|
||||
- This comment is longer.
|
||||
- These two lines are rendered as bullets by GraphiQL.
|
||||
"#]
|
||||
field attr_description_long() -> i32 { 0 }
|
||||
|
||||
#[deprecated]
|
||||
field attr_deprecated() -> i32 { 0 }
|
||||
|
||||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_reason() -> i32 { 0 }
|
||||
|
||||
#[doc = "Field description"]
|
||||
#[deprecated(note = "Deprecation reason")]
|
||||
field attr_deprecated_descr() -> i32 { 0 }
|
||||
|
||||
instance_resolvers: |&_| {
|
||||
Root => Some(Root {}),
|
||||
}
|
||||
|
@ -280,3 +330,255 @@ fn introspect_interface_field_deprecated_descr() {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_object_field_attr_description() {
|
||||
run_field_info_query("Root", "attrDescription", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDescription"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Field description"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(false))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_interface_field_attr_description() {
|
||||
run_field_info_query("Interface", "attrDescription", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDescription"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Field description"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(false))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_object_field_attr_description_long() {
|
||||
run_field_info_query("Root", "attrDescriptionLong", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDescriptionLong"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Get the i32 representation of 0.\n\n- This comment is longer.\n- These two lines are rendered as bullets by GraphiQL."))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(false))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_interface_field_attr_description_long() {
|
||||
run_field_info_query("Interface", "attrDescriptionLong", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDescriptionLong"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Get the i32 representation of 0.\n\n- This comment is longer.\n- These two lines are rendered as bullets by GraphiQL."))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(false))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_object_field_attr_description_collapse() {
|
||||
run_field_info_query("Root", "attrDescriptionCollapse", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDescriptionCollapse"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Field description\nwith `collapse_docs` behavior"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(false))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_interface_field_attr_description_collapse() {
|
||||
run_field_info_query("Interface", "attrDescriptionCollapse", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDescriptionCollapse"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Field description\nwith `collapse_docs` behavior"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(false))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_object_field_attr_deprecated() {
|
||||
run_field_info_query("Root", "attrDeprecated", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDeprecated"))
|
||||
);
|
||||
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(true))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_interface_field_attr_deprecated() {
|
||||
run_field_info_query("Interface", "attrDeprecated", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDeprecated"))
|
||||
);
|
||||
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(true))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::null())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_object_field_attr_deprecated_reason() {
|
||||
run_field_info_query("Root", "attrDeprecatedReason", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDeprecatedReason"))
|
||||
);
|
||||
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(true))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::scalar("Deprecation reason"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_interface_field_attr_deprecated_reason() {
|
||||
run_field_info_query("Interface", "attrDeprecatedReason", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDeprecatedReason"))
|
||||
);
|
||||
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(true))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::scalar("Deprecation reason"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_object_field_attr_deprecated_descr() {
|
||||
run_field_info_query("Root", "attrDeprecatedDescr", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDeprecatedDescr"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Field description"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(true))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::scalar("Deprecation reason"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn introspect_interface_field_attr_deprecated_descr() {
|
||||
run_field_info_query("Interface", "attrDeprecatedDescr", |field| {
|
||||
assert_eq!(
|
||||
field.get_field_value("name"),
|
||||
Some(&Value::scalar("attrDeprecatedDescr"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("description"),
|
||||
Some(&Value::scalar("Field description"))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("isDeprecated"),
|
||||
Some(&Value::scalar(true))
|
||||
);
|
||||
assert_eq!(
|
||||
field.get_field_value("deprecationReason"),
|
||||
Some(&Value::scalar("Deprecation reason"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,6 +9,33 @@ use schema::model::SchemaType;
|
|||
use types::base::TypeKind;
|
||||
use value::{DefaultScalarValue, ParseScalarValue, ScalarRefValue, ScalarValue};
|
||||
|
||||
/// Whether an item is deprecated, with context.
|
||||
#[derive(Debug, PartialEq, Hash, Clone)]
|
||||
pub enum DeprecationStatus {
|
||||
/// The field/variant is not deprecated.
|
||||
Current,
|
||||
/// The field/variant is deprecated, with an optional reason
|
||||
Deprecated(Option<String>),
|
||||
}
|
||||
|
||||
impl DeprecationStatus {
|
||||
/// If this deprecation status indicates the item is deprecated.
|
||||
pub fn is_deprecated(&self) -> bool {
|
||||
match self {
|
||||
&DeprecationStatus::Current => false,
|
||||
&DeprecationStatus::Deprecated(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// An optional reason for the deprecation, or none if `Current`.
|
||||
pub fn reason(&self) -> Option<&String> {
|
||||
match self {
|
||||
&DeprecationStatus::Current => None,
|
||||
&DeprecationStatus::Deprecated(ref reason) => reason.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Scalar type metadata
|
||||
pub struct ScalarMeta<'a, S> {
|
||||
#[doc(hidden)]
|
||||
|
@ -135,7 +162,7 @@ pub struct Field<'a, S> {
|
|||
#[doc(hidden)]
|
||||
pub field_type: Type<'a>,
|
||||
#[doc(hidden)]
|
||||
pub deprecation_reason: Option<String>,
|
||||
pub deprecation_status: DeprecationStatus,
|
||||
}
|
||||
|
||||
/// Metadata for an argument to a field
|
||||
|
@ -163,10 +190,8 @@ pub struct EnumValue {
|
|||
/// Note: this is not the description of the enum itself; it's the
|
||||
/// description of this enum _value_.
|
||||
pub description: Option<String>,
|
||||
/// The optional deprecation reason
|
||||
///
|
||||
/// If this is `Some`, the field will be considered `isDeprecated`.
|
||||
pub deprecation_reason: Option<String>,
|
||||
/// Whether the field is deprecated or not, with an optional reason.
|
||||
pub deprecation_status: DeprecationStatus,
|
||||
}
|
||||
|
||||
impl<'a, S> MetaType<'a, S> {
|
||||
|
@ -580,6 +605,28 @@ impl<'a, S> Field<'a, S> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Adds a (multi)line doc string to the description of the field.
|
||||
/// Any leading or trailing newlines will be removed.
|
||||
///
|
||||
/// If the docstring contains newlines, repeated leading tab and space characters
|
||||
/// will be removed from the beginning of each line.
|
||||
///
|
||||
/// If the description hasn't been set, the description is set to the provided line.
|
||||
/// Otherwise, the doc string is added to the current description after a newline.
|
||||
pub fn push_docstring(mut self, multiline: &str) -> Field<'a, S> {
|
||||
let docstring = clean_docstring(multiline);
|
||||
match &mut self.description {
|
||||
&mut Some(ref mut desc) => {
|
||||
desc.push('\n');
|
||||
desc.push_str(&docstring);
|
||||
}
|
||||
desc @ &mut None => {
|
||||
*desc = Some(docstring.to_string());
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an argument to the field
|
||||
///
|
||||
/// Arguments are unordered and can't contain duplicates by name.
|
||||
|
@ -596,11 +643,11 @@ impl<'a, S> Field<'a, S> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set the deprecation reason
|
||||
/// Set the field to be deprecated with an optional reason.
|
||||
///
|
||||
/// This overwrites the deprecation reason if any was previously set.
|
||||
pub fn deprecated(mut self, reason: &str) -> Self {
|
||||
self.deprecation_reason = Some(reason.to_owned());
|
||||
pub fn deprecated(mut self, reason: Option<&str>) -> Self {
|
||||
self.deprecation_status = DeprecationStatus::Deprecated(reason.map(|s| s.to_owned()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -624,6 +671,28 @@ impl<'a, S> Argument<'a, S> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Adds a (multi)line doc string to the description of the field.
|
||||
/// Any leading or trailing newlines will be removed.
|
||||
///
|
||||
/// If the docstring contains newlines, repeated leading tab and space characters
|
||||
/// will be removed from the beginning of each line.
|
||||
///
|
||||
/// If the description hasn't been set, the description is set to the provided line.
|
||||
/// Otherwise, the doc string is added to the current description after a newline.
|
||||
pub fn push_docstring(mut self, multiline: &str) -> Argument<'a, S> {
|
||||
let docstring = clean_docstring(multiline);
|
||||
match &mut self.description {
|
||||
&mut Some(ref mut desc) => {
|
||||
desc.push('\n');
|
||||
desc.push_str(&docstring);
|
||||
}
|
||||
desc @ &mut None => {
|
||||
*desc = Some(docstring.to_string());
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default value of the argument
|
||||
///
|
||||
/// This overwrites the description if any was previously set.
|
||||
|
@ -639,7 +708,7 @@ impl EnumValue {
|
|||
EnumValue {
|
||||
name: name.to_owned(),
|
||||
description: None,
|
||||
deprecation_reason: None,
|
||||
deprecation_status: DeprecationStatus::Current,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -651,11 +720,11 @@ impl EnumValue {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set the deprecation reason for the enum value
|
||||
/// Set the enum value to be deprecated with an optional reason.
|
||||
///
|
||||
/// This overwrites the deprecation reason if any was previously set.
|
||||
pub fn deprecated(mut self, reason: &str) -> EnumValue {
|
||||
self.deprecation_reason = Some(reason.to_owned());
|
||||
pub fn deprecated(mut self, reason: Option<&str>) -> Self {
|
||||
self.deprecation_status = DeprecationStatus::Deprecated(reason.map(|s| s.to_owned()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -696,3 +765,27 @@ where
|
|||
{
|
||||
<T as FromInputValue<S>>::from_input_value(v).is_some()
|
||||
}
|
||||
|
||||
fn clean_docstring<'a>(multiline: &'a str) -> Cow<'a, str> {
|
||||
let trim_start = multiline.split('\n')
|
||||
.skip(1)
|
||||
.filter_map(|ln| ln.chars().position(|ch| ch != ' ' && ch != '\t'))
|
||||
.min();
|
||||
if let Some(trim) = trim_start {
|
||||
let trimmed = multiline
|
||||
.split('\n')
|
||||
.map(|ln| {
|
||||
if !ln.starts_with(' ') && !ln.starts_with('\t') {
|
||||
ln // skip trimming the first line
|
||||
} else if ln.len() >= trim {
|
||||
&ln[trim..]
|
||||
} else {
|
||||
""
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Cow::from(trimmed.join("\n").trim_matches('\n').to_owned())
|
||||
} else {
|
||||
Cow::from(multiline.trim_matches('\n'))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ graphql_object!(<'a> TypeType<'a, S>: SchemaType<'a, S> as "__Type"
|
|||
TypeType::Concrete(&MetaType::Object(ObjectMeta { ref fields, .. })) =>
|
||||
Some(fields
|
||||
.iter()
|
||||
.filter(|f| include_deprecated || f.deprecation_reason.is_none())
|
||||
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
||||
.filter(|f| !f.name.starts_with("__"))
|
||||
.collect()),
|
||||
_ => None,
|
||||
|
@ -201,7 +201,7 @@ graphql_object!(<'a> TypeType<'a, S>: SchemaType<'a, S> as "__Type"
|
|||
TypeType::Concrete(&MetaType::Enum(EnumMeta { ref values, .. })) =>
|
||||
Some(values
|
||||
.iter()
|
||||
.filter(|f| include_deprecated || f.deprecation_reason.is_none())
|
||||
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
||||
.collect()),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -228,11 +228,11 @@ graphql_object!(<'a> Field<'a, S>: SchemaType<'a, S> as "__Field"
|
|||
}
|
||||
|
||||
field is_deprecated() -> bool {
|
||||
self.deprecation_reason.is_some()
|
||||
self.deprecation_status.is_deprecated()
|
||||
}
|
||||
|
||||
field deprecation_reason() -> &Option<String> {
|
||||
&self.deprecation_reason
|
||||
field deprecation_reason() -> Option<&String> {
|
||||
self.deprecation_status.reason()
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -266,11 +266,11 @@ graphql_object!(EnumValue: () as "__EnumValue" where Scalar = <S> |&self| {
|
|||
}
|
||||
|
||||
field is_deprecated() -> bool {
|
||||
self.deprecation_reason.is_some()
|
||||
self.deprecation_status.is_deprecated()
|
||||
}
|
||||
|
||||
field deprecation_reason() -> &Option<String> {
|
||||
&self.deprecation_reason
|
||||
field deprecation_reason() -> Option<&String> {
|
||||
self.deprecation_status.reason()
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ impl EnumAttrs {
|
|||
continue;
|
||||
}
|
||||
panic!(format!(
|
||||
"Unknown attribute for #[derive(GraphQLEnum)]: {:?}",
|
||||
"Unknown enum attribute for #[derive(GraphQLEnum)]: {:?}",
|
||||
item
|
||||
));
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ impl EnumAttrs {
|
|||
struct EnumVariantAttrs {
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
deprecation: Option<String>,
|
||||
deprecation: Option<DeprecationAttr>,
|
||||
}
|
||||
|
||||
impl EnumVariantAttrs {
|
||||
|
@ -67,6 +67,9 @@ impl EnumVariantAttrs {
|
|||
// Check doc comments for description.
|
||||
res.description = get_doc_comment(&variant.attrs);
|
||||
|
||||
// Check builtin deprecated attribute for deprecation.
|
||||
res.deprecation = get_deprecated(&variant.attrs);
|
||||
|
||||
// Check attributes for name and description.
|
||||
if let Some(items) = get_graphql_attr(&variant.attrs) {
|
||||
for item in items {
|
||||
|
@ -90,13 +93,24 @@ impl EnumVariantAttrs {
|
|||
continue;
|
||||
}
|
||||
if let Some(AttributeValue::String(val)) =
|
||||
keyed_item_value(&item, "deprecated", AttributeValidation::String)
|
||||
keyed_item_value(&item, "deprecation", AttributeValidation::String)
|
||||
{
|
||||
res.deprecation = Some(val);
|
||||
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||
continue;
|
||||
}
|
||||
match keyed_item_value(&item, "deprecated", AttributeValidation::String) {
|
||||
Some(AttributeValue::String(val)) => {
|
||||
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||
continue;
|
||||
}
|
||||
Some(AttributeValue::Bare) => {
|
||||
res.deprecation = Some(DeprecationAttr { reason: None });
|
||||
continue;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
panic!(format!(
|
||||
"Unknown attribute for #[derive(GraphQLEnum)]: {:?}",
|
||||
"Unknown variant attribute for #[derive(GraphQLEnum)]: {:?}",
|
||||
item
|
||||
));
|
||||
}
|
||||
|
@ -151,14 +165,21 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
|
|||
None => quote!{ None },
|
||||
};
|
||||
let depr = match var_attrs.deprecation {
|
||||
Some(s) => quote!{ Some(#s.to_string()) },
|
||||
None => quote!{ None },
|
||||
Some(DeprecationAttr { reason: Some(s) }) => quote!{
|
||||
_juniper::meta::DeprecationStatus::Deprecated(Some(#s.to_string()))
|
||||
},
|
||||
Some(DeprecationAttr { reason: None }) => quote!{
|
||||
_juniper::meta::DeprecationStatus::Deprecated(None)
|
||||
},
|
||||
None => quote!{
|
||||
_juniper::meta::DeprecationStatus::Current
|
||||
},
|
||||
};
|
||||
values.extend(quote!{
|
||||
_juniper::meta::EnumValue{
|
||||
name: #name.to_string(),
|
||||
description: #descr,
|
||||
deprecation_reason: #depr,
|
||||
deprecation_status: #depr,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ impl ObjAttrs {
|
|||
continue;
|
||||
}
|
||||
panic!(format!(
|
||||
"Unknown object attribute for #[derive(GraphQLObject)]: {:?}",
|
||||
"Unknown struct attribute for #[derive(GraphQLObject)]: {:?}",
|
||||
item
|
||||
));
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ impl ObjAttrs {
|
|||
struct ObjFieldAttrs {
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
deprecation: Option<String>,
|
||||
deprecation: Option<DeprecationAttr>,
|
||||
skip: bool,
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,9 @@ impl ObjFieldAttrs {
|
|||
// Check doc comments for description.
|
||||
res.description = get_doc_comment(&variant.attrs);
|
||||
|
||||
// Check builtin deprecated attribute for deprecation.
|
||||
res.deprecation = get_deprecated(&variant.attrs);
|
||||
|
||||
// Check attributes.
|
||||
if let Some(items) = get_graphql_attr(&variant.attrs) {
|
||||
for item in items {
|
||||
|
@ -96,9 +99,20 @@ impl ObjFieldAttrs {
|
|||
if let Some(AttributeValue::String(val)) =
|
||||
keyed_item_value(&item, "deprecation", AttributeValidation::String)
|
||||
{
|
||||
res.deprecation = Some(val);
|
||||
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||
continue;
|
||||
}
|
||||
match keyed_item_value(&item, "deprecated", AttributeValidation::String) {
|
||||
Some(AttributeValue::String(val)) => {
|
||||
res.deprecation = Some(DeprecationAttr { reason: Some(val) });
|
||||
continue;
|
||||
}
|
||||
Some(AttributeValue::Bare) => {
|
||||
res.deprecation = Some(DeprecationAttr { reason: None });
|
||||
continue;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if let Some(_) = keyed_item_value(&item, "skip", AttributeValidation::Bare) {
|
||||
res.skip = true;
|
||||
continue;
|
||||
|
@ -167,7 +181,8 @@ pub fn impl_object(ast: &syn::DeriveInput) -> TokenStream {
|
|||
};
|
||||
|
||||
let build_deprecation = match field_attrs.deprecation {
|
||||
Some(s) => quote!{ field.deprecated(#s) },
|
||||
Some(DeprecationAttr { reason: Some(s) }) => quote!{ field.deprecated(Some(#s)) },
|
||||
Some(DeprecationAttr { reason: None }) => quote!{ field.deprecated(None) },
|
||||
None => quote!{ field },
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use regex::Regex;
|
||||
use syn::{Attribute, Lit, Meta, MetaNameValue, NestedMeta};
|
||||
use syn::{Attribute, Lit, Meta, MetaList, MetaNameValue, NestedMeta};
|
||||
|
||||
pub enum AttributeValidation {
|
||||
Any,
|
||||
|
@ -12,6 +12,42 @@ pub enum AttributeValue {
|
|||
String(String),
|
||||
}
|
||||
|
||||
pub struct DeprecationAttr {
|
||||
pub reason: Option<String>,
|
||||
}
|
||||
|
||||
pub fn get_deprecated(attrs: &Vec<Attribute>) -> Option<DeprecationAttr> {
|
||||
for attr in attrs {
|
||||
match attr.interpret_meta() {
|
||||
Some(Meta::List(ref list)) if list.ident == "deprecated" => {
|
||||
return Some(get_deprecated_meta_list(list));
|
||||
}
|
||||
Some(Meta::Word(ref ident)) if ident == "deprecated" => {
|
||||
return Some(DeprecationAttr { reason: None });
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_deprecated_meta_list(list: &MetaList) -> DeprecationAttr {
|
||||
for meta in &list.nested {
|
||||
match meta {
|
||||
&NestedMeta::Meta(Meta::NameValue(ref nv)) if nv.ident == "note" => {
|
||||
match &nv.lit {
|
||||
&Lit::Str(ref strlit) => {
|
||||
return DeprecationAttr { reason: Some(strlit.value().to_string()) };
|
||||
}
|
||||
_ => panic!("deprecated attribute note value only has string literal"),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
DeprecationAttr { reason: None }
|
||||
}
|
||||
|
||||
// Gets doc comment.
|
||||
pub fn get_doc_comment(attrs: &Vec<Attribute>) -> Option<String> {
|
||||
if let Some(items) = get_doc_attr(attrs) {
|
||||
|
|
|
@ -78,7 +78,7 @@ impl<'a> GraphQLType for &'a Fake {
|
|||
&[juniper::meta::EnumValue {
|
||||
name: "fake".to_string(),
|
||||
description: None,
|
||||
deprecation_reason: None,
|
||||
deprecation_status: juniper::meta::DeprecationStatus::Current,
|
||||
}],
|
||||
);
|
||||
meta.into_meta()
|
||||
|
|
Loading…
Reference in a new issue