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

Opt in the null safety #259

Closed
wants to merge 8 commits into from
Closed
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
## 6.19.1-beta.1
- Append typename flag

## 6.18.3
- fix for the case when multiple documents were included in request https://github.com/comigor/artemis/issues/251

## 6.18.2
- Merging beta into master

Expand Down
2 changes: 0 additions & 2 deletions lib/artemis.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.8

export 'client.dart';
export 'schema/graphql_query.dart';
export 'schema/graphql_response.dart';
26 changes: 12 additions & 14 deletions lib/builder.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.8

import 'dart:async';

import 'package:artemis/generator/data/data.dart';
Expand Down Expand Up @@ -37,7 +35,7 @@ Please check your build.yaml file.

return schemaMaps
.map((s) {
final outputWithoutLib = s.output.replaceAll(RegExp(r'^lib/'), '');
final outputWithoutLib = s.output!.replaceAll(RegExp(r'^lib/'), '');

return {
outputWithoutLib,
Expand Down Expand Up @@ -65,7 +63,7 @@ class GraphQLQueryBuilder implements Builder {
final List<String> expectedOutputs;

/// Callback fired when the generator processes a [QueryDefinition].
OnBuildQuery onBuild;
OnBuildQuery? onBuild;

@override
Map<String, List<String>> get buildExtensions => {
Expand All @@ -75,7 +73,7 @@ class GraphQLQueryBuilder implements Builder {
@override
Future<void> build(BuildStep buildStep) async {
if (options.fragmentsGlob != null) {
final fragmentStream = buildStep.findAssets(Glob(options.fragmentsGlob));
final fragmentStream = buildStep.findAssets(Glob(options.fragmentsGlob!));
final fDocs = await fragmentStream
.asyncMap(
(asset) async => parseString(
Expand All @@ -93,20 +91,20 @@ class GraphQLQueryBuilder implements Builder {
for (final schemaMap in options.schemaMapping) {
final buffer = StringBuffer();
final outputFileId = AssetId(buildStep.inputId.package,
_addGraphQLExtensionToPathIfNeeded(schemaMap.output));
_addGraphQLExtensionToPathIfNeeded(schemaMap.output!));

// Loop through all files in glob
if (schemaMap.queriesGlob == null) {
throw Exception('''No queries were considered on this generation!
Make sure that `queries_glob` your build.yaml file include GraphQL queries files.
''');
} else if (Glob(schemaMap.queriesGlob).matches(schemaMap.schema)) {
} else if (Glob(schemaMap.queriesGlob!).matches(schemaMap.schema!)) {
throw QueryGlobsSchemaException();
} else if (Glob(schemaMap.queriesGlob).matches(schemaMap.output)) {
} else if (Glob(schemaMap.queriesGlob!).matches(schemaMap.output!)) {
throw QueryGlobsOutputException();
}

final assetStream = buildStep.findAssets(Glob(schemaMap.queriesGlob));
final assetStream = buildStep.findAssets(Glob(schemaMap.queriesGlob!));
var gqlDocs = await assetStream
.asyncMap(
(asset) async => parseString(
Expand Down Expand Up @@ -139,7 +137,7 @@ Make sure that `queries_glob` your build.yaml file include GraphQL queries files
.toList();
}

final schemaAssetStream = buildStep.findAssets(Glob(schemaMap.schema));
final schemaAssetStream = buildStep.findAssets(Glob(schemaMap.schema!));

DocumentNode gqlSchema;

Expand All @@ -161,15 +159,15 @@ ${e}
}

final libDefinition = generateLibrary(
_addGraphQLExtensionToPathIfNeeded(schemaMap.output),
_addGraphQLExtensionToPathIfNeeded(schemaMap.output!),
gqlDocs,
options,
schemaMap,
fragmentsCommon,
gqlSchema,
);
if (onBuild != null) {
onBuild(libDefinition);
onBuild!(libDefinition);
}
writeLibraryDefinitionToBuffer(
buffer,
Expand All @@ -179,9 +177,9 @@ ${e}

await buildStep.writeAsString(outputFileId, buffer.toString());

if (!schemaMap.output.endsWith('.graphql.dart')) {
if (!schemaMap.output!.endsWith('.graphql.dart')) {
final forwarderOutputFileId =
AssetId(buildStep.inputId.package, schemaMap.output);
AssetId(buildStep.inputId.package, schemaMap.output!);
await buildStep.writeAsString(
forwarderOutputFileId, writeLibraryForwarder(libDefinition));
}
Expand Down
14 changes: 6 additions & 8 deletions lib/client.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @dart = 2.8

import 'dart:async';

import 'package:gql_dedupe_link/gql_dedupe_link.dart';
Expand All @@ -16,7 +14,7 @@ import './schema/graphql_response.dart';
///
/// A [Link] is used as the network interface.
class ArtemisClient {
HttpLink _httpLink;
HttpLink? _httpLink;
final Link _link;

/// Instantiate an [ArtemisClient].
Expand All @@ -25,7 +23,7 @@ class ArtemisClient {
/// To use different [Link] create an [ArtemisClient] with [ArtemisClient.fromLink].
factory ArtemisClient(
String graphQLEndpoint, {
http.Client httpClient,
http.Client? httpClient,
}) {
final httpLink = HttpLink(
graphQLEndpoint,
Expand All @@ -48,7 +46,7 @@ class ArtemisClient {
) async {
final request = Request(
operation: Operation(
document: query.document,
document: query.document!,
operationName: query.operationName,
),
variables: query.getVariablesMap(),
Expand All @@ -57,7 +55,7 @@ class ArtemisClient {
final response = await _link.request(request).first;

return GraphQLResponse<T>(
data: response.data == null ? null : query.parse(response.data),
data: response.data == null ? null : query.parse(response.data!),
errors: response.errors,
);
}
Expand All @@ -68,14 +66,14 @@ class ArtemisClient {
) {
final request = Request(
operation: Operation(
document: query.document,
document: query.document!,
operationName: query.operationName,
),
variables: query.getVariablesMap(),
);

return _link.request(request).map((response) => GraphQLResponse<T>(
data: response.data == null ? null : query.parse(response.data),
data: response.data == null ? null : query.parse(response.data!),
errors: response.errors,
));
}
Expand Down
51 changes: 27 additions & 24 deletions lib/generator.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
// @dart = 2.8

import 'package:artemis/generator/data/data.dart';
import 'package:artemis/generator/data/enum_value_definition.dart';
import 'package:artemis/visitor/canonical_visitor.dart';
import 'package:artemis/visitor/generator_visitor.dart';
import 'package:artemis/visitor/object_type_definition_visitor.dart';
import 'package:artemis/visitor/schema_definition_visitor.dart';
import 'package:artemis/visitor/type_definition_node_visitor.dart';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:gql/ast.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as p;

import './generator/ephemeral_data.dart';
Expand Down Expand Up @@ -89,7 +87,7 @@ LibraryDefinition generateLibrary(
);
}

Set<FragmentDefinitionNode> _extractFragments(SelectionSetNode selectionSet,
Set<FragmentDefinitionNode> _extractFragments(SelectionSetNode? selectionSet,
List<FragmentDefinitionNode> fragmentsCommon) {
final result = <FragmentDefinitionNode>{};
if (selectionSet != null) {
Expand Down Expand Up @@ -175,19 +173,19 @@ Iterable<QueryDefinition> generateDefinitions(

final rootTypeName =
(schemaVisitor.schemaDefinitionNode?.operationTypes ?? [])
.firstWhere((e) => e.operation == operation.type,
orElse: () => null)
.firstWhereOrNull((e) => e.operation == operation.type)
?.type
?.name
?.value ??
.name
.value ??
suffix;

if (rootTypeName == null) {
throw Exception(
'''No root type was found for ${operation.type} $operationName.''');
}

final TypeDefinitionNode parentType = objectVisitor.getByName(rootTypeName);
final TypeDefinitionNode parentType =
objectVisitor.getByName(rootTypeName)!;

final name = QueryName.fromPath(
path: createPathName([
Expand Down Expand Up @@ -217,17 +215,20 @@ Iterable<QueryDefinition> generateDefinitions(
context: context,
);

DocumentNode(
final filteredDefinition = DocumentNode(
definitions: document.definitions
// filtering unused operations
.where((e) => e is! OperationDefinitionNode || e == operation)
.toList(),
).accept(visitor);
.where((e) {
return e is! OperationDefinitionNode || e == operation;
}).toList(),
);

filteredDefinition.accept(visitor);

return QueryDefinition(
name: name,
operationName: operationName,
document: document,
document: filteredDefinition,
classes: [
...canonicalVisitor.enums
.where((e) => context.usedEnums.contains(e.name)),
Expand Down Expand Up @@ -260,17 +261,18 @@ List<String> _extractCustomImports(

/// Creates class property object
ClassProperty createClassProperty({
@required ClassPropertyName fieldName,
ClassPropertyName fieldAlias,
@required Context context,
_OnNewClassFoundCallback onNewClassFound,
required ClassPropertyName fieldName,
ClassPropertyName? fieldAlias,
required Context context,
_OnNewClassFoundCallback? onNewClassFound,
bool markAsUsed = true,
}) {
if (fieldName.name == context.schemaMap.typeNameField) {
return ClassProperty(
type: TypeName(name: 'String'),
name: fieldName,
annotations: ['JsonKey(name: \'${context.schemaMap.typeNameField}\')'],
isNonNull: true,
isResolveType: true,
);
}
Expand All @@ -287,16 +289,16 @@ ClassProperty createClassProperty({

final regularField = finalFields
.whereType<FieldDefinitionNode>()
.firstWhere((f) => f.name.value == fieldName.name, orElse: () => null);
.firstWhereOrNull((f) => f.name.value == fieldName.name);
final regularInputField = finalFields
.whereType<InputValueDefinitionNode>()
.firstWhere((f) => f.name.value == fieldName.name, orElse: () => null);
.firstWhereOrNull((f) => f.name.value == fieldName.name);

final fieldType = regularField?.type ?? regularInputField?.type;

if (fieldType == null) {
throw Exception(
'''Field $fieldName was not found in GraphQL type ${context.currentType?.name?.value}.
'''Field $fieldName was not found in GraphQL type ${context.currentType?.name.value}.
Make sure your query is correct and your schema is updated.''');
}

Expand All @@ -317,7 +319,7 @@ Make sure your query is correct and your schema is updated.''');
schema: context.schema);

logFn(context, aliasedContext.align + 1,
'${aliasedContext.path}[${aliasedContext.currentType.name.value}][${aliasedContext.currentClassName} ${aliasedContext.currentFieldName}] ${fieldAlias == null ? '' : '(${fieldAlias}) '}-> ${dartTypeName.namePrintable}');
'${aliasedContext.path}[${aliasedContext.currentType!.name.value}][${aliasedContext.currentClassName} ${aliasedContext.currentFieldName}] ${fieldAlias == null ? '' : '(${fieldAlias}) '}-> ${dartTypeName.namePrintable}');

if ((nextType is ObjectTypeDefinitionNode ||
nextType is UnionTypeDefinitionNode ||
Expand All @@ -327,7 +329,7 @@ Make sure your query is correct and your schema is updated.''');
aliasedContext.next(
nextType: nextType,
nextFieldName: ClassPropertyName(
name: regularField?.name?.value ?? regularInputField?.name?.value),
name: regularField?.name.value ?? regularInputField?.name.value),
nextClassName: ClassName(name: nextType.name.value),
alias: fieldAlias,
),
Expand All @@ -343,7 +345,8 @@ Make sure your query is correct and your schema is updated.''');
}

if (nextType is ScalarTypeDefinitionNode) {
final scalar = gql.getSingleScalarMap(context.options, nextType.name.value);
final scalar =
gql.getSingleScalarMap(context.options, nextType.name.value)!;

if (scalar.customParserImport != null &&
nextType.name.value == scalar.graphQLType) {
Expand Down
23 changes: 10 additions & 13 deletions lib/generator/data/class_definition.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// @dart = 2.8

import 'package:artemis/generator/data/class_property.dart';
import 'package:artemis/generator/data/definition.dart';
import 'package:artemis/generator/data/fragment_class_definition.dart';
import 'package:artemis/generator/data_printer.dart';
import 'package:artemis/generator/helpers.dart';
import 'package:meta/meta.dart';
import 'package:recase/recase.dart';

/// Define a Dart class parsed from GraphQL type.
Expand All @@ -14,7 +11,7 @@ class ClassDefinition extends Definition with DataPrinter {
final Iterable<ClassProperty> properties;

/// The type this class extends from, or [null].
final Name extension;
final Name? extension;

/// The types this class implements.
final Iterable<String> implementations;
Expand All @@ -34,20 +31,20 @@ class ClassDefinition extends Definition with DataPrinter {

/// Instantiate a class definition.
ClassDefinition({
@required Name name,
required Name name,
this.properties = const [],
this.extension,
this.implementations = const [],
this.mixins = const [],
this.factoryPossibilities = const {},
TypeName typeNameField,
TypeName? typeNameField,
this.isInput = false,
}) : assert(hasValue(name)),
typeNameField = typeNameField ?? TypeName(name: '__typename'),
super(name: name);

@override
Map<String, Object> get namedProps => {
Map<String, Object?> get namedProps => {
'name': name,
'properties': properties,
'extension': extension,
Expand All @@ -62,20 +59,20 @@ class ClassDefinition extends Definition with DataPrinter {
/// Class name.
class ClassName extends Name with DataPrinter {
/// Instantiate a class name definition.
ClassName({String name}) : super(name: name);
ClassName({String? name}) : super(name: name);

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

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

@override
String normalize(String name) {
return ReCase(super.normalize(name)).pascalCase;
String normalize(String? name) {
return ReCase(super.normalize(name)!).pascalCase;
}
}
Loading