Skip to content

Commit f571db1

Browse files
committed
Merge branch 'issue-7-deprecated'
2 parents ef26736 + d333b3a commit f571db1

File tree

10 files changed

+187
-27
lines changed

10 files changed

+187
-27
lines changed

crates/cli/src/check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use log::{debug, info};
44

55
use graphql_builtins::generate_builtins;
66
use nitrogql_checker::{check_operation_document, check_type_system_document};
7-
use nitrogql_error::{print_positioned_error, Result};
7+
use nitrogql_error::Result;
88
use nitrogql_semantics::{ast_to_type_system, resolve_extensions};
99

1010
use crate::{context::LoadedSchema, output::InputFileKind};

crates/cli/src/output/mod.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ impl CliOutput {
3939
self.command_error = Some((command_name, error));
4040
}
4141

42-
/// Add a check error.
43-
pub fn check_error(&mut self, kind: InputFileKind, error: CheckError) {
44-
self.check_errors.push((kind, error));
45-
}
46-
4742
/// Add a generated file.
4843
pub fn generated_file(&mut self, kind: OutputFileKind, path: PathBuf) {
4944
self.generated_files.push((kind, path));

crates/introspection/src/introspection.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ struct IntrospectionField<'src> {
5959
#[serde(rename = "type")]
6060
ty: IntrospectionType<'src>,
6161
#[serde(rename = "isDeprecated")]
62-
#[allow(dead_code)]
63-
is_deprecated: bool,
62+
is_deprecated: Option<bool>,
6463
#[serde(rename = "deprecationReason")]
65-
#[allow(dead_code)]
6664
deprecation_reason: Option<Cow<'src, str>>,
6765
}
6866

@@ -74,17 +72,19 @@ struct IntrospectionInputValue<'src> {
7472
ty: IntrospectionType<'src>,
7573
#[serde(rename = "defaultValue")]
7674
default_value: Option<Cow<'src, str>>,
75+
#[serde(rename = "isDeprecated")]
76+
is_deprecated: Option<bool>,
77+
#[serde(rename = "deprecationReason")]
78+
deprecation_reason: Option<Cow<'src, str>>,
7779
}
7880

7981
#[derive(Deserialize)]
8082
struct IntrospectionEnumValue<'src> {
8183
name: Cow<'src, str>,
8284
description: Option<Cow<'src, str>>,
8385
#[serde(rename = "isDeprecated")]
84-
#[allow(dead_code)]
85-
is_deprecated: bool,
86+
is_deprecated: Option<bool>,
8687
#[serde(rename = "deprecationReason")]
87-
#[allow(dead_code)]
8888
deprecation_reason: Option<Cow<'src, str>>,
8989
}
9090

@@ -262,8 +262,16 @@ fn as_type_definition<'src, D: Default>(
262262
.map(|ev| {
263263
let name = node_clone(&ev.name);
264264
let description = ev.description.as_ref().map(node_clone);
265-
266-
EnumMember { name, description }
265+
let deprecation = ev
266+
.is_deprecated
267+
.unwrap_or(false)
268+
.then(|| ev.deprecation_reason.as_ref().cloned().unwrap_or_default());
269+
270+
EnumMember {
271+
name,
272+
description,
273+
deprecation,
274+
}
267275
})
268276
.collect();
269277

@@ -305,12 +313,20 @@ fn as_field<'src, D: Default>(
305313
.map(as_input_value)
306314
.collect::<Result<_, _>>()
307315
.unwrap_or(vec![]);
316+
let deprecation = value.is_deprecated.unwrap_or(false).then(|| {
317+
value
318+
.deprecation_reason
319+
.as_ref()
320+
.cloned()
321+
.unwrap_or_default()
322+
});
308323

309324
Ok(Field {
310325
name,
311326
description,
312327
r#type: ty,
313328
arguments,
329+
deprecation,
314330
})
315331
}
316332

@@ -321,12 +337,20 @@ fn as_input_value<'src, D: Default>(
321337
let description = value.description.as_ref().map(node_clone);
322338
let ty = as_type(&value.ty)?;
323339
let default_value = value.default_value.as_ref().map(node_clone);
340+
let deprecation = value.is_deprecated.unwrap_or(false).then(|| {
341+
value
342+
.deprecation_reason
343+
.as_ref()
344+
.cloned()
345+
.unwrap_or_default()
346+
});
324347

325348
Ok(InputValue {
326349
name,
327350
description,
328351
r#type: ty,
329352
default_value,
353+
deprecation,
330354
})
331355
}
332356

crates/printer/src/schema_type_printer/tests/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,35 @@ fn scalar_printing() {
134134
assert_snapshot!(printed);
135135
}
136136

137+
#[test]
138+
fn deprecated_items() {
139+
let doc = parse_type_system_document(
140+
r#"
141+
type User {
142+
id: ID!
143+
name: String!
144+
"Age of user."
145+
age: Int @deprecated
146+
gender: String @deprecated(reason: "Deprecated for political reasons")
147+
}
148+
149+
input UserSearchQuery {
150+
age: Int @deprecated
151+
name: String
152+
}
153+
154+
type Query {
155+
me: User!
156+
}
157+
"#,
158+
)
159+
.unwrap();
160+
let doc = resolve_extensions(doc).unwrap();
161+
let options = SchemaTypePrinterOptions::default();
162+
let printed = print_document(&doc, options).unwrap();
163+
assert_snapshot!(printed);
164+
}
165+
137166
fn print_document(
138167
document: &TypeSystemDocument,
139168
options: SchemaTypePrinterOptions,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
source: crates/printer/src/schema_type_printer/tests/mod.rs
3+
expression: printed
4+
---
5+
export type __nitrogql_schema = {
6+
query: Query;
7+
};
8+
9+
type __Beautify<Obj> = { [K in keyof Obj]: Obj[K] } & {};
10+
export type __SelectionSet<Orig, Obj, Others> =
11+
__Beautify<Pick<{
12+
[K in keyof Orig]: Obj extends Record<K, infer V> ? V : unknown
13+
}, Extract<keyof Orig, keyof Obj>> & Others>;
14+
export type User = {
15+
__typename: "User";
16+
id: ID;
17+
name: String;
18+
/**
19+
* Age of user.
20+
* @deprecated No longer supported
21+
*/
22+
age: Int | null;
23+
/**
24+
* @deprecated Deprecated for political reasons
25+
*/
26+
gender: String | null;
27+
};
28+
29+
export type Query = {
30+
__typename: "Query";
31+
me: User;
32+
};
33+
34+
export type UserSearchQuery = {
35+
/**
36+
* @deprecated No longer supported
37+
*/
38+
readonly age?: Int | null;
39+
readonly name?: String | null;
40+
};
41+
42+

crates/printer/src/schema_type_printer/type_printer.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::borrow::Borrow;
1+
use std::{borrow::Borrow, fmt::Display};
22

33
use crate::{
44
ts_types::{
@@ -72,7 +72,7 @@ fn get_schema_metadata_type(document: &TypeSystemDocument) -> TSType {
7272
(
7373
op.as_str(),
7474
TSType::TypeVariable(ty.into()),
75-
schema_def.description.clone(),
75+
schema_def.description.as_ref().map(|d| d.value.clone()),
7676
)
7777
}));
7878
}
@@ -171,13 +171,14 @@ impl TypePrinter for ScalarTypeDefinition<'_> {
171171
impl TypePrinter for ObjectTypeDefinition<'_> {
172172
fn print_type(
173173
&self,
174-
_context: &SchemaTypePrinterContext,
174+
context: &SchemaTypePrinterContext,
175175
writer: &mut impl SourceMapWriter,
176176
) -> SchemaTypePrinterResult<()> {
177177
let type_name_ident = Ident {
178178
name: "__typename",
179179
position: Pos::builtin(),
180180
};
181+
let schema_type = context.schema.get_type(self.name.name);
181182
let obj_type = TSType::object(
182183
vec![(
183184
&type_name_ident,
@@ -186,12 +187,18 @@ impl TypePrinter for ObjectTypeDefinition<'_> {
186187
)]
187188
.into_iter()
188189
.chain(self.fields.iter().map(|field| {
190+
let schema_field = schema_type
191+
.and_then(|ty| ty.as_object())
192+
.and_then(|ty| ty.fields.iter().find(|f| f.name == field.name.name));
189193
(
190194
&field.name,
191195
get_ts_type_of_type(&field.r#type, |name| {
192196
TSType::TypeVariable((&name.name).into())
193197
}),
194-
field.description.clone(),
198+
make_ts_description(
199+
&field.description,
200+
&schema_field.and_then(|f| f.deprecation.as_ref()),
201+
),
195202
)
196203
})),
197204
);
@@ -283,10 +290,16 @@ impl TypePrinter for InputObjectTypeDefinition<'_> {
283290
context: &SchemaTypePrinterContext,
284291
writer: &mut impl SourceMapWriter,
285292
) -> SchemaTypePrinterResult<()> {
293+
let schema_type = context.schema.get_type(self.name.name);
286294
let obj_type = TSType::Object(
287295
self.fields
288296
.iter()
289297
.map(|field| {
298+
let schema_field = schema_type
299+
.and_then(|t| t.as_input_object())
300+
.and_then(|t| t.fields.iter().find(|f| f.name == field.name.name))
301+
.expect("Type system error");
302+
290303
let ts_type = get_ts_type_of_type(&field.r#type, |name| {
291304
TSType::TypeVariable((&name.name).into())
292305
})
@@ -297,7 +310,10 @@ impl TypePrinter for InputObjectTypeDefinition<'_> {
297310
readonly: true,
298311
optional: context.options.input_nullable_field_is_optional
299312
&& !field.r#type.is_nonnull(),
300-
description: field.description.clone(),
313+
description: make_ts_description(
314+
&field.description,
315+
&schema_field.deprecation,
316+
),
301317
}
302318
})
303319
.collect(),
@@ -318,3 +334,19 @@ fn print_description(description: &Option<StringValue>, writer: &mut impl Source
318334
jsdoc_print_description(description, writer);
319335
}
320336
}
337+
338+
/// Combines description and deprecation reason into a single string.
339+
fn make_ts_description(
340+
description: &Option<StringValue>,
341+
deprecation: &Option<impl Display>,
342+
) -> Option<String> {
343+
match (description, deprecation) {
344+
(Some(description), Some(deprecation)) => Some(format!(
345+
"{}\n\n@deprecated {}",
346+
description.value, deprecation
347+
)),
348+
(Some(description), None) => Some(description.value.clone()),
349+
(None, Some(deprecation)) => format!("@deprecated {}", deprecation).into(),
350+
(None, None) => None,
351+
}
352+
}

crates/printer/src/ts_types/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use nitrogql_ast::{
2-
base::{HasPos, Ident, Pos},
3-
value::StringValue,
4-
};
1+
use nitrogql_ast::base::{HasPos, Ident, Pos};
52
use sourcemap_writer::SourceMapWriter;
63

74
use super::jsdoc::print_description;
@@ -84,7 +81,7 @@ pub struct ObjectField {
8481
pub r#type: TSType,
8582
pub readonly: bool,
8683
pub optional: bool,
87-
pub description: Option<StringValue>,
84+
pub description: Option<String>,
8885
}
8986

9087
#[derive(Clone, Debug)]
@@ -158,7 +155,7 @@ impl TSType {
158155
writer.indent();
159156
for field in properties {
160157
if let Some(ref description) = field.description {
161-
print_description(&description.value, writer);
158+
print_description(description, writer);
162159
}
163160
if field.readonly {
164161
writer.write("readonly ");
@@ -268,7 +265,7 @@ impl TSType {
268265

269266
/// Creates an object type from given set of non-readonly, non-optional properties.
270267
pub fn object<S: Into<ObjectKey>>(
271-
properties: impl IntoIterator<Item = (S, TSType, Option<StringValue>)>,
268+
properties: impl IntoIterator<Item = (S, TSType, Option<String>)>,
272269
) -> TSType {
273270
TSType::Object(
274271
properties

crates/semantics/src/ast_to_type_system.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ use graphql_type_system::{
77
};
88
use nitrogql_ast::{
99
base::{HasPos, Pos},
10+
directive::Directive,
1011
operation::OperationType,
1112
type_system::{
1213
ArgumentsDefinition, DirectiveDefinition as AstDirectiveDefinition, FieldDefinition,
1314
SchemaDefinition, TypeDefinition as AstTypeDefinition, TypeSystemDefinition,
1415
},
15-
value::StringValue,
16+
value::{StringValue, Value},
1617
TypeSystemDocument,
1718
};
1819

@@ -124,6 +125,7 @@ fn convert_type_definition<'src>(
124125
.map(|mem| EnumMember {
125126
name: ident_to_node(&mem.name),
126127
description: convert_description(&mem.description),
128+
deprecation: convert_deprecation(&mem.directives),
127129
})
128130
.collect(),
129131
}),
@@ -150,6 +152,7 @@ fn convert_type_definition<'src>(
150152
let value_disp = Box::leak(value_disp);
151153
Node::from(&*value_disp, *value.position())
152154
}),
155+
deprecation: convert_deprecation(&input.directives),
153156
})
154157
.collect(),
155158
}),
@@ -205,6 +208,7 @@ fn convert_arguments<'src>(
205208
let value_disp = Box::leak(value_disp);
206209
Node::from(&*value_disp, *value.position())
207210
}),
211+
deprecation: convert_deprecation(&input.directives),
208212
})
209213
.collect()
210214
})
@@ -216,5 +220,27 @@ fn convert_field<'src>(field: &FieldDefinition<'src>) -> Field<Cow<'src, str>, P
216220
description: convert_description(&field.description),
217221
r#type: convert_type(&field.r#type),
218222
arguments: convert_arguments(&field.arguments),
223+
deprecation: convert_deprecation(&field.directives),
219224
}
220225
}
226+
227+
fn convert_deprecation<'src>(directives: &[Directive<'src>]) -> Option<Cow<'src, str>> {
228+
directives
229+
.iter()
230+
.find(|dir| dir.name.name == "deprecated")
231+
.map(|dir| {
232+
dir.arguments
233+
.iter()
234+
.flat_map(|args| args.arguments.iter())
235+
.find(|(name, _)| name.name == "reason")
236+
.map(|(_, value)| value)
237+
.and_then(|value| match value {
238+
Value::StringValue(string) => Some(Cow::Owned(string.value.clone())),
239+
_ => None,
240+
})
241+
.unwrap_or(
242+
// Default value is from the spec
243+
Cow::Borrowed("No longer supported"),
244+
)
245+
})
246+
}

0 commit comments

Comments
 (0)