diff --git a/packages/graphql_codegen/README.md b/packages/graphql_codegen/README.md index c0e46895..06d409b1 100644 --- a/packages/graphql_codegen/README.md +++ b/packages/graphql_codegen/README.md @@ -283,19 +283,20 @@ targets: # all options go here ``` -| Option | Default | Description | More info | -| -------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -| `clients` | {} | Graphql clients to generate helper functions for. Supported types are `graphql` and `graphql_flutter` | [Clients](#clients) | -| `scalars` | {} | Allows custom JSON-Dart transformations. Builder will warn if scalars are not recognized. Unless using primitive types, you will need `fromJsonFunctionName`, `toJsonFunctionName`, `type`, and `import` | [Custom scalars](#custom-scalars) | -| `enums` | {} | Allows custom enum implementation. You can define `fromJsonFunctionName`, `toJsonFunctionName`, `type`, and `import` | [Custom enums](#custom-enums) | -| `addTypename` | true | Whether to automatically insert the `__typename` field in requests | [Add typename](#add-typename) | -| `addTypenameExcludedPaths` | [] | When `addTypename` is true, the paths to exclude | [Excluding typenames](#excluding-some-selections-from-adding-typename) | -| `outputDirectory` | "." | Location where to output generated types relative to each `.graphql` file | [Change output directory](#change-output-directory) | -| `assetsPath` | "lib/\*\*.graphql" | Path to `.graphql` files | **see above** | -| `generatedFileHeader` | "" | A string to add at the beginning of all `graphql.dart` files | [Generated file headers](#generated-file-headers) | -| `scopes` | ["**.graphql"] | For multiple schemas, the globs for each schema | [Multiple Schemas](#multiple-schemas) | -| `namingSeparator` | "$" | The separator to use for generated names | [Change naming separator](#change-naming-separator) | -| `extraKeywords` | [] | A way to specify fields that are also keywords | [Extra keywords](#extra-keywords) | +| Option | Default | Description | More info | +| --------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| `clients` | {} | Graphql clients to generate helper functions for. Supported types are `graphql` and `graphql_flutter` | [Clients](#clients) | +| `scalars` | {} | Allows custom JSON-Dart transformations. Builder will warn if scalars are not recognized. Unless using primitive types, you will need `fromJsonFunctionName`, `toJsonFunctionName`, `type`, and `import` | [Custom scalars](#custom-scalars) | +| `enums` | {} | Allows custom enum implementation. You can define `fromJsonFunctionName`, `toJsonFunctionName`, `type`, and `import` | [Custom enums](#custom-enums) | +| `addTypename` | true | Whether to automatically insert the `__typename` field in requests | [Add typename](#add-typename) | +| `addTypenameExcludedPaths` | [] | When `addTypename` is true, the paths to exclude | [Excluding typenames](#excluding-some-selections-from-adding-typename) | +| `outputDirectory` | "." | Location where to output generated types relative to each `.graphql` file | [Change output directory](#change-output-directory) | +| `assetsPath` | "lib/\*\*.graphql" | Path to `.graphql` files | **see above** | +| `generatedFileHeader` | "" | A string to add at the beginning of all `graphql.dart` files | [Generated file headers](#generated-file-headers) | +| `scopes` | ["**.graphql"] | For multiple schemas, the globs for each schema | [Multiple Schemas](#multiple-schemas) | +| `namingSeparator` | "$" | The separator to use for generated names | [Change naming separator](#change-naming-separator) | +| `extraKeywords` | [] | A way to specify fields that are also keywords | [Extra keywords](#extra-keywords) | +| `disableCopyWithGeneration` | `false` | Allow you to disable generation of copy-with classes and methods | | --- diff --git a/packages/graphql_codegen/lib/src/config/config.dart b/packages/graphql_codegen/lib/src/config/config.dart index ea11fcbb..306df583 100644 --- a/packages/graphql_codegen/lib/src/config/config.dart +++ b/packages/graphql_codegen/lib/src/config/config.dart @@ -66,6 +66,7 @@ class GraphQLCodegenConfig { final List extraKeywords; final String outputDirectory; final bool disableContextReplacement; + final bool disableCopyWithGeneration; GraphQLCodegenConfig({ this.clients = const {}, @@ -80,6 +81,7 @@ class GraphQLCodegenConfig { this.namingSeparator = r"$", this.extraKeywords = const [], this.outputDirectory = '.', + this.disableCopyWithGeneration = false, }); @override diff --git a/packages/graphql_codegen/lib/src/config/config.g.dart b/packages/graphql_codegen/lib/src/config/config.g.dart index fd130db5..5944ec6b 100644 --- a/packages/graphql_codegen/lib/src/config/config.g.dart +++ b/packages/graphql_codegen/lib/src/config/config.g.dart @@ -82,6 +82,8 @@ GraphQLCodegenConfig _$GraphQLCodegenConfigFromJson( .toList() ?? const [], outputDirectory: json['outputDirectory'] as String? ?? '.', + disableCopyWithGeneration: + json['disableCopyWithGeneration'] as bool? ?? false, ); Map _$GraphQLCodegenConfigToJson( @@ -101,6 +103,7 @@ Map _$GraphQLCodegenConfigToJson( 'extraKeywords': instance.extraKeywords, 'outputDirectory': instance.outputDirectory, 'disableContextReplacement': instance.disableContextReplacement, + 'disableCopyWithGeneration': instance.disableCopyWithGeneration, }; const _$GraphQLCodegenConfigClientEnumMap = { diff --git a/packages/graphql_codegen/lib/src/printer/base/document.dart b/packages/graphql_codegen/lib/src/printer/base/document.dart index 6aee62c2..724b3643 100644 --- a/packages/graphql_codegen/lib/src/printer/base/document.dart +++ b/packages/graphql_codegen/lib/src/printer/base/document.dart @@ -150,6 +150,11 @@ Class printContext(PrintContext c) { List printContextExtension(PrintContext c) { final context = c.context; + + if (context.config.disableCopyWithGeneration) { + return []; + } + final properties = c.context.properties; final whenMethod = _printWhen( diff --git a/packages/graphql_codegen/lib/src/printer/base/input.dart b/packages/graphql_codegen/lib/src/printer/base/input.dart index d95c52e3..873bf50f 100644 --- a/packages/graphql_codegen/lib/src/printer/base/input.dart +++ b/packages/graphql_codegen/lib/src/printer/base/input.dart @@ -132,21 +132,23 @@ List _printInputClasses( ..returns = dynamicMap ..body = _printToJson(context, properties), ), - Method( - (b) => b - ..name = 'copyWith' - ..type = MethodType.getter - ..returns = generic( - context.namePrinter.printCopyWithClassName(name(context.path)), - refer(name(context.path)), - ) - ..body = refer(context.namePrinter - .printCopyWithClassName(name(context.path))) - .call([ - refer('this'), - printIdentityFunction().closure, - ]).code, - ), + if (!context.context.config.disableCopyWithGeneration) + Method( + (b) => b + ..name = 'copyWith' + ..type = MethodType.getter + ..returns = generic( + context.namePrinter + .printCopyWithClassName(name(context.path)), + refer(name(context.path)), + ) + ..body = refer(context.namePrinter + .printCopyWithClassName(name(context.path))) + .call([ + refer('this'), + printIdentityFunction().closure, + ]).code, + ), printEqualityOperator( context, name(context.path), @@ -160,31 +162,32 @@ List _printInputClasses( ), ]), ), - ...printCopyWithClasses( - context, - name(context.path), - properties, - refer(name(context.path)).property('_').call([ - CodeExpression(Block.of([ - Code('{'), - Code('..._instance.${kDataVariableName},'), - ...properties.expand((prop) { - final propName = context.namePrinter.printPropertyName(prop.name); - return [ - if (prop.isNonNull) - Code('if(${propName} != _undefined && ${propName} != null)') - else - Code('if(${propName} != _undefined)'), - literalString(prop.name.value).code, - Code(':'), - refer(propName).asA(printClassPropertyType(context, prop)).code, - Code(','), - ]; - }), - Code('}'), - ])), - ]), - ) + if (!context.context.config.disableCopyWithGeneration) + ...printCopyWithClasses( + context, + name(context.path), + properties, + refer(name(context.path)).property('_').call([ + CodeExpression(Block.of([ + Code('{'), + Code('..._instance.${kDataVariableName},'), + ...properties.expand((prop) { + final propName = context.namePrinter.printPropertyName(prop.name); + return [ + if (prop.isNonNull) + Code('if(${propName} != _undefined && ${propName} != null)') + else + Code('if(${propName} != _undefined)'), + literalString(prop.name.value).code, + Code(':'), + refer(propName).asA(printClassPropertyType(context, prop)).code, + Code(','), + ]; + }), + Code('}'), + ])), + ]), + ) ]; } diff --git a/packages/graphql_codegen/test/assets/disable_copy_with/document.graphql b/packages/graphql_codegen/test/assets/disable_copy_with/document.graphql new file mode 100644 index 00000000..b64e977d --- /dev/null +++ b/packages/graphql_codegen/test/assets/disable_copy_with/document.graphql @@ -0,0 +1,13 @@ +scalar DateTime + +type Query { + time: DateTime +} + +query FetchScalars { + time +} + +input CreateScalar { + time: DateTime +} diff --git a/packages/graphql_codegen/test/assets/disable_copy_with/document.graphql.dart b/packages/graphql_codegen/test/assets/disable_copy_with/document.graphql.dart new file mode 100644 index 00000000..b5cfbe35 --- /dev/null +++ b/packages/graphql_codegen/test/assets/disable_copy_with/document.graphql.dart @@ -0,0 +1,323 @@ +import 'package:gql/ast.dart'; + +class Input$CreateScalar { + factory Input$CreateScalar({String? time}) => Input$CreateScalar._({ + if (time != null) r'time': time, + }); + + Input$CreateScalar._(this._$data); + + factory Input$CreateScalar.fromJson(Map data) { + final result$data = {}; + if (data.containsKey('time')) { + final l$time = data['time']; + result$data['time'] = (l$time as String?); + } + return Input$CreateScalar._(result$data); + } + + Map _$data; + + String? get time => (_$data['time'] as String?); + + Map toJson() { + final result$data = {}; + if (_$data.containsKey('time')) { + final l$time = time; + result$data['time'] = l$time; + } + return result$data; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (!(other is Input$CreateScalar) || runtimeType != other.runtimeType) { + return false; + } + final l$time = time; + final lOther$time = other.time; + if (_$data.containsKey('time') != other._$data.containsKey('time')) { + return false; + } + if (l$time != lOther$time) { + return false; + } + return true; + } + + @override + int get hashCode { + final l$time = time; + return Object.hashAll([_$data.containsKey('time') ? l$time : const {}]); + } +} + +enum Enum$__TypeKind { + SCALAR, + OBJECT, + INTERFACE, + UNION, + ENUM, + INPUT_OBJECT, + LIST, + NON_NULL, + $unknown; + + factory Enum$__TypeKind.fromJson(String value) => + fromJson$Enum$__TypeKind(value); + + String toJson() => toJson$Enum$__TypeKind(this); +} + +String toJson$Enum$__TypeKind(Enum$__TypeKind e) { + switch (e) { + case Enum$__TypeKind.SCALAR: + return r'SCALAR'; + case Enum$__TypeKind.OBJECT: + return r'OBJECT'; + case Enum$__TypeKind.INTERFACE: + return r'INTERFACE'; + case Enum$__TypeKind.UNION: + return r'UNION'; + case Enum$__TypeKind.ENUM: + return r'ENUM'; + case Enum$__TypeKind.INPUT_OBJECT: + return r'INPUT_OBJECT'; + case Enum$__TypeKind.LIST: + return r'LIST'; + case Enum$__TypeKind.NON_NULL: + return r'NON_NULL'; + case Enum$__TypeKind.$unknown: + return r'$unknown'; + } +} + +Enum$__TypeKind fromJson$Enum$__TypeKind(String value) { + switch (value) { + case r'SCALAR': + return Enum$__TypeKind.SCALAR; + case r'OBJECT': + return Enum$__TypeKind.OBJECT; + case r'INTERFACE': + return Enum$__TypeKind.INTERFACE; + case r'UNION': + return Enum$__TypeKind.UNION; + case r'ENUM': + return Enum$__TypeKind.ENUM; + case r'INPUT_OBJECT': + return Enum$__TypeKind.INPUT_OBJECT; + case r'LIST': + return Enum$__TypeKind.LIST; + case r'NON_NULL': + return Enum$__TypeKind.NON_NULL; + default: + return Enum$__TypeKind.$unknown; + } +} + +enum Enum$__DirectiveLocation { + QUERY, + MUTATION, + SUBSCRIPTION, + FIELD, + FRAGMENT_DEFINITION, + FRAGMENT_SPREAD, + INLINE_FRAGMENT, + VARIABLE_DEFINITION, + SCHEMA, + SCALAR, + OBJECT, + FIELD_DEFINITION, + ARGUMENT_DEFINITION, + INTERFACE, + UNION, + ENUM, + ENUM_VALUE, + INPUT_OBJECT, + INPUT_FIELD_DEFINITION, + $unknown; + + factory Enum$__DirectiveLocation.fromJson(String value) => + fromJson$Enum$__DirectiveLocation(value); + + String toJson() => toJson$Enum$__DirectiveLocation(this); +} + +String toJson$Enum$__DirectiveLocation(Enum$__DirectiveLocation e) { + switch (e) { + case Enum$__DirectiveLocation.QUERY: + return r'QUERY'; + case Enum$__DirectiveLocation.MUTATION: + return r'MUTATION'; + case Enum$__DirectiveLocation.SUBSCRIPTION: + return r'SUBSCRIPTION'; + case Enum$__DirectiveLocation.FIELD: + return r'FIELD'; + case Enum$__DirectiveLocation.FRAGMENT_DEFINITION: + return r'FRAGMENT_DEFINITION'; + case Enum$__DirectiveLocation.FRAGMENT_SPREAD: + return r'FRAGMENT_SPREAD'; + case Enum$__DirectiveLocation.INLINE_FRAGMENT: + return r'INLINE_FRAGMENT'; + case Enum$__DirectiveLocation.VARIABLE_DEFINITION: + return r'VARIABLE_DEFINITION'; + case Enum$__DirectiveLocation.SCHEMA: + return r'SCHEMA'; + case Enum$__DirectiveLocation.SCALAR: + return r'SCALAR'; + case Enum$__DirectiveLocation.OBJECT: + return r'OBJECT'; + case Enum$__DirectiveLocation.FIELD_DEFINITION: + return r'FIELD_DEFINITION'; + case Enum$__DirectiveLocation.ARGUMENT_DEFINITION: + return r'ARGUMENT_DEFINITION'; + case Enum$__DirectiveLocation.INTERFACE: + return r'INTERFACE'; + case Enum$__DirectiveLocation.UNION: + return r'UNION'; + case Enum$__DirectiveLocation.ENUM: + return r'ENUM'; + case Enum$__DirectiveLocation.ENUM_VALUE: + return r'ENUM_VALUE'; + case Enum$__DirectiveLocation.INPUT_OBJECT: + return r'INPUT_OBJECT'; + case Enum$__DirectiveLocation.INPUT_FIELD_DEFINITION: + return r'INPUT_FIELD_DEFINITION'; + case Enum$__DirectiveLocation.$unknown: + return r'$unknown'; + } +} + +Enum$__DirectiveLocation fromJson$Enum$__DirectiveLocation(String value) { + switch (value) { + case r'QUERY': + return Enum$__DirectiveLocation.QUERY; + case r'MUTATION': + return Enum$__DirectiveLocation.MUTATION; + case r'SUBSCRIPTION': + return Enum$__DirectiveLocation.SUBSCRIPTION; + case r'FIELD': + return Enum$__DirectiveLocation.FIELD; + case r'FRAGMENT_DEFINITION': + return Enum$__DirectiveLocation.FRAGMENT_DEFINITION; + case r'FRAGMENT_SPREAD': + return Enum$__DirectiveLocation.FRAGMENT_SPREAD; + case r'INLINE_FRAGMENT': + return Enum$__DirectiveLocation.INLINE_FRAGMENT; + case r'VARIABLE_DEFINITION': + return Enum$__DirectiveLocation.VARIABLE_DEFINITION; + case r'SCHEMA': + return Enum$__DirectiveLocation.SCHEMA; + case r'SCALAR': + return Enum$__DirectiveLocation.SCALAR; + case r'OBJECT': + return Enum$__DirectiveLocation.OBJECT; + case r'FIELD_DEFINITION': + return Enum$__DirectiveLocation.FIELD_DEFINITION; + case r'ARGUMENT_DEFINITION': + return Enum$__DirectiveLocation.ARGUMENT_DEFINITION; + case r'INTERFACE': + return Enum$__DirectiveLocation.INTERFACE; + case r'UNION': + return Enum$__DirectiveLocation.UNION; + case r'ENUM': + return Enum$__DirectiveLocation.ENUM; + case r'ENUM_VALUE': + return Enum$__DirectiveLocation.ENUM_VALUE; + case r'INPUT_OBJECT': + return Enum$__DirectiveLocation.INPUT_OBJECT; + case r'INPUT_FIELD_DEFINITION': + return Enum$__DirectiveLocation.INPUT_FIELD_DEFINITION; + default: + return Enum$__DirectiveLocation.$unknown; + } +} + +class Query$FetchScalars { + Query$FetchScalars({ + this.time, + this.$__typename = 'Query', + }); + + factory Query$FetchScalars.fromJson(Map json) { + final l$time = json['time']; + final l$$__typename = json['__typename']; + return Query$FetchScalars( + time: (l$time as String?), + $__typename: (l$$__typename as String), + ); + } + + final String? time; + + final String $__typename; + + Map toJson() { + final _resultData = {}; + final l$time = time; + _resultData['time'] = l$time; + final l$$__typename = $__typename; + _resultData['__typename'] = l$$__typename; + return _resultData; + } + + @override + int get hashCode { + final l$time = time; + final l$$__typename = $__typename; + return Object.hashAll([ + l$time, + l$$__typename, + ]); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (!(other is Query$FetchScalars) || runtimeType != other.runtimeType) { + return false; + } + final l$time = time; + final lOther$time = other.time; + if (l$time != lOther$time) { + return false; + } + final l$$__typename = $__typename; + final lOther$$__typename = other.$__typename; + if (l$$__typename != lOther$$__typename) { + return false; + } + return true; + } +} + +const documentNodeQueryFetchScalars = DocumentNode(definitions: [ + OperationDefinitionNode( + type: OperationType.query, + name: NameNode(value: 'FetchScalars'), + variableDefinitions: [], + directives: [], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'time'), + alias: null, + arguments: [], + directives: [], + selectionSet: null, + ), + FieldNode( + name: NameNode(value: '__typename'), + alias: null, + arguments: [], + directives: [], + selectionSet: null, + ), + ]), + ), +]); +const possibleTypesMap = >{}; diff --git a/packages/graphql_codegen/test/assets/disable_copy_with/options.json b/packages/graphql_codegen/test/assets/disable_copy_with/options.json new file mode 100644 index 00000000..ce468cc8 --- /dev/null +++ b/packages/graphql_codegen/test/assets/disable_copy_with/options.json @@ -0,0 +1,3 @@ +{ + "disableCopyWithGeneration": true +}