Skip to content
This repository has been archived by the owner on Oct 2, 2024. It is now read-only.

Commit

Permalink
Merge pull request #275 from comigor/non-nullable
Browse files Browse the repository at this point in the history
Non-nullable by default output
  • Loading branch information
comigor authored Mar 18, 2021
2 parents f54c339 + 0ce654f commit e6e05e1
Show file tree
Hide file tree
Showing 61 changed files with 1,739 additions and 1,953 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## 7.0.0-beta.1
**MAJOR BREAKING CHANGE**

- Code generated by Artemis is now nnbd-compliant

## 6.20.1-beta.2
- Add codespaces folder

Expand Down
9 changes: 4 additions & 5 deletions lib/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,9 @@ Make sure your query is correct and your schema is updated.''');
.dartTypeSafe);
final dartTypeSafeStr = TypeName(name: dartTypeName.dartTypeSafe);
jsonKeyAnnotation['fromJson'] =
'fromGraphQL${graphqlTypeSafeStr.namePrintable}ToDart${dartTypeSafeStr.namePrintable}';
'fromGraphQL${graphqlTypeSafeStr.dartTypeSafe}ToDart${dartTypeSafeStr.dartTypeSafe}';
jsonKeyAnnotation['toJson'] =
'fromDart${dartTypeSafeStr.namePrintable}ToGraphQL${graphqlTypeSafeStr.namePrintable}';
'fromDart${dartTypeSafeStr.dartTypeSafe}ToGraphQL${graphqlTypeSafeStr.dartTypeSafe}';
}
} // On enums
else if (nextType is EnumTypeDefinitionNode) {
Expand All @@ -371,10 +371,10 @@ Make sure your query is correct and your schema is updated.''');
replaceLeafWith: ClassName.fromPath(path: nextClassName),
schema: context.schema);
jsonKeyAnnotation['unknownEnumValue'] =
'${innerDartTypeName.namePrintable}.${ARTEMIS_UNKNOWN.name.namePrintable}';
'${innerDartTypeName.dartTypeSafe}.${ARTEMIS_UNKNOWN.name.namePrintable}';
} else {
jsonKeyAnnotation['unknownEnumValue'] =
'${dartTypeName.namePrintable}.${ARTEMIS_UNKNOWN.name.namePrintable}';
'${dartTypeName.dartTypeSafe}.${ARTEMIS_UNKNOWN.name.namePrintable}';
}
}

Expand All @@ -395,6 +395,5 @@ Make sure your query is correct and your schema is updated.''');
type: dartTypeName,
name: name,
annotations: annotations,
isNonNull: fieldType.isNonNull,
);
}
8 changes: 4 additions & 4 deletions lib/generator/data/class_definition.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class ClassDefinition extends Definition with DataPrinter {
final Map<String, Name> factoryPossibilities;

/// The field name used to resolve this class type.
final TypeName typeNameField;
final ClassPropertyName typeNameField;

/// Whether this is an input object or not.
final bool isInput;
Expand All @@ -40,10 +40,10 @@ class ClassDefinition extends Definition with DataPrinter {
this.implementations = const [],
this.mixins = const [],
this.factoryPossibilities = const {},
TypeName typeNameField,
ClassPropertyName typeNameField,
this.isInput = false,
}) : assert(hasValue(name)),
typeNameField = typeNameField ?? TypeName(name: '__typename'),
typeNameField = typeNameField ?? ClassPropertyName(name: '__typename'),
super(name: name);

@override
Expand All @@ -66,7 +66,7 @@ class ClassName extends Name with DataPrinter {

/// Generate class name from hierarchical path
factory ClassName.fromPath({List<Name> path}) {
return ClassName(name: path.map((e) => e.namePrintable).join(r'$_'));
return ClassName(name: path.map((e) => e.dartTypeSafe).join(r'$_'));
}

@override
Expand Down
51 changes: 41 additions & 10 deletions lib/generator/data/class_property.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,13 @@ class ClassProperty extends Definition with DataPrinter {
/// Some other custom annotation.
final List<String> annotations;

/// Whether this parameter is required
final bool isNonNull;

/// Whether this parameter corresponds to the __resolveType (or equivalent)
final bool isResolveType;

/// Instantiate a property (field) from a class.
ClassProperty({
@required this.type,
this.annotations = const [],
this.isNonNull = false,
this.isResolveType = false,
@required this.name,
}) : assert(hasValue(type) && hasValue(name)),
Expand All @@ -41,14 +37,12 @@ class ClassProperty extends Definition with DataPrinter {
TypeName type,
ClassPropertyName name,
List<String> annotations,
bool isNonNull,
bool isResolveType,
}) =>
ClassProperty(
type: type ?? this.type,
name: name ?? this.name,
annotations: annotations ?? this.annotations,
isNonNull: isNonNull ?? this.isNonNull,
isResolveType: isResolveType ?? this.isResolveType,
);

Expand All @@ -57,7 +51,6 @@ class ClassProperty extends Definition with DataPrinter {
'type': type,
'name': name,
'annotations': annotations,
'isNonNull': isNonNull,
'isResolveType': isResolveType,
};
}
Expand Down Expand Up @@ -85,18 +78,56 @@ const _camelCaseTypes = {'bool', 'double', 'int'};
/// Type name
class TypeName extends Name with DataPrinter {
/// Instantiate a type name definition.
TypeName({String name}) : super(name: name);
TypeName({
String name,
this.isNonNull = false,
}) : super(name: name);

/// If this type is non-null
final bool isNonNull;

@override
Map<String, Object> get namedProps => {
'name': name,
if (isNonNull) 'isNonNull': true,
};

@override
List get props => [name, isNonNull];

@override
String normalize(String name) {
final normalized = super.normalize(name);
if (_camelCaseTypes.contains(normalized)) return normalized;
if (_camelCaseTypes.contains(normalized)) {
return '$normalized${isNonNull ? '' : '?'}';
}

return ReCase(normalized).pascalCase;
return '${ReCase(normalized).pascalCase}${isNonNull ? '' : '?'}';
}
}

/// Type name
class ListOfTypeName extends TypeName with DataPrinter {
/// Instantiate a type name definition.
ListOfTypeName({
this.typeName,
this.isNonNull = true,
}) : super(name: typeName.name, isNonNull: isNonNull);

/// Internal type name
final TypeName typeName;

/// If this list type is non-null
@override
final bool isNonNull;

@override
Map<String, Object> get namedProps => {
'typeName': typeName,
'isNonNull': isNonNull,
};

@override
String normalize(String name) =>
'List<${typeName.namePrintable}>${isNonNull ? '' : '?'}';
}
2 changes: 1 addition & 1 deletion lib/generator/data/definition.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ abstract class Name extends Equatable with DataPrinter {
String get namePrintable => normalize(name);

/// type name safe to use for dart
String get dartTypeSafe => namePrintable.replaceAll(RegExp(r'[<>]'), '');
String get dartTypeSafe => namePrintable.replaceAll(RegExp(r'[<>?]'), '');

/// Name normalization function
String normalize(String name) => normalizeName(name);
Expand Down
2 changes: 1 addition & 1 deletion lib/generator/data/fragment_class_definition.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class FragmentName extends Name with DataPrinter {

/// Generate class name from hierarchical path
factory FragmentName.fromPath({List<Name> path}) {
return FragmentName(name: path.map((e) => e.namePrintable).join(r'$_'));
return FragmentName(name: path.map((e) => e.dartTypeSafe).join(r'$_'));
}

@override
Expand Down
2 changes: 1 addition & 1 deletion lib/generator/data/query_definition.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class QueryName extends Name with DataPrinter {

/// Generate class name from hierarchical path
factory QueryName.fromPath({List<Name> path}) {
return QueryName(name: path.map((e) => e.namePrintable).join(r'$_'));
return QueryName(name: path.map((e) => e.dartTypeSafe).join(r'$_'));
}

@override
Expand Down
5 changes: 0 additions & 5 deletions lib/generator/data/query_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,12 @@ class QueryInput extends Definition with DataPrinter {
/// The input type.
final TypeName type;

/// Whether this parameter is required
final bool isNonNull;

/// Some other custom annotation.
final List<String> annotations;

/// Instantiate an input parameter.
QueryInput({
@required this.type,
this.isNonNull = false,
this.annotations = const [],
this.name,
}) : assert(hasValue(type) && hasValue(name)),
Expand All @@ -33,7 +29,6 @@ class QueryInput extends Definition with DataPrinter {
Map<String, Object> get namedProps => {
'type': type,
'name': name,
'isNonNull': isNonNull,
'annotations': annotations,
};
}
Expand Down
17 changes: 11 additions & 6 deletions lib/generator/graphql_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,33 @@ TypeName buildTypeName(
if (type is ScalarTypeDefinitionNode) {
final scalar = getSingleScalarMap(options, node.name.value);
return TypeName(
name: dartType ? scalar.dartType.name : scalar.graphQLType);
name: dartType ? scalar.dartType.name : scalar.graphQLType,
isNonNull: node.isNonNull,
);
}

if (type is EnumTypeDefinitionNode ||
type is InputObjectTypeDefinitionNode) {
return TypeName(name: type.name.value);
return TypeName(name: type.name.value, isNonNull: node.isNonNull);
}

if (replaceLeafWith != null) {
return TypeName(name: replaceLeafWith.name);
return TypeName(name: replaceLeafWith.name, isNonNull: node.isNonNull);
} else {
return TypeName(name: type.name.value);
return TypeName(name: type.name.value, isNonNull: node.isNonNull);
}
}

return TypeName(name: node.name.value);
return TypeName(name: node.name.value, isNonNull: node.isNonNull);
}

if (node is ListTypeNode) {
final typeName = buildTypeName(node.type, options,
dartType: dartType, replaceLeafWith: replaceLeafWith, schema: schema);
return TypeName(name: 'List<${typeName.namePrintable}>');
return ListOfTypeName(
typeName: typeName,
isNonNull: node.isNonNull,
);
}

throw Exception('Unable to build type name');
Expand Down
21 changes: 0 additions & 21 deletions lib/generator/helpers.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// @dart = 2.8

import 'package:artemis/generator/data/data.dart';
import 'package:artemis/generator/ephemeral_data.dart';
import 'package:build/build.dart';
import 'package:gql/ast.dart';
Expand Down Expand Up @@ -133,26 +132,6 @@ extension ExtensionsOnIterable<T, U> on Iterable<T> {
_removeDuplicatedBy(this, fn);
}

/// Checks if the passed queries contain either:
/// - A [ClassDefinition] that's an input object with at least one non nullable
/// property.
/// - A [QueryInput] which is non nullable.
bool hasNonNullableInput(Iterable<QueryDefinition> queries) {
for (final query in queries) {
for (final clazz in query.classes.whereType<ClassDefinition>()) {
if (clazz.isInput && clazz.properties.any((p) => p.isNonNull)) {
return true;
}
}

if (query.inputs.any((i) => i.isNonNull)) {
return true;
}
}

return false;
}

/// Check if [obj] has value (isn't null or empty).
bool hasValue(Object obj) {
if (obj is Iterable) {
Expand Down
Loading

0 comments on commit e6e05e1

Please sign in to comment.