Skip to content

Commit

Permalink
feat: configuration of default scalar type (#5699)
Browse files Browse the repository at this point in the history
* feat: configuration of default scalar type

* fixup! feat: configuration of default scalar type

* test: add tests

* fixup! feat: configuration of default scalar type

* fixup! test: add tests

* changeset
  • Loading branch information
andreialecu committed Apr 19, 2021
1 parent b7ef363 commit 097bea2
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 27 deletions.
14 changes: 14 additions & 0 deletions .changeset/wild-rules-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@graphql-codegen/c-sharp': minor
'@graphql-codegen/c-sharp-operations': minor
'@graphql-codegen/java': minor
'@graphql-codegen/kotlin': minor
'@graphql-codegen/java-resolvers': minor
'@graphql-codegen/visitor-plugin-common': minor
'@graphql-codegen/typescript-compatibility': minor
'@graphql-codegen/typescript-mongodb': minor
'@graphql-codegen/typescript': minor
'@graphql-codegen/near-operation-file-preset': minor
---

Added new configuration settings for scalars: `strictScalars` and `defaultScalarType`
4 changes: 2 additions & 2 deletions packages/plugins/c-sharp/c-sharp-operations/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
LoadedFragment,
indentMultiline,
getBaseTypeNode,
buildScalars,
indent,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import autoBind from 'auto-bind';
import {
Expand Down Expand Up @@ -88,7 +88,7 @@ export class CSharpOperationsVisitor extends ClientSideBaseVisitor<
querySuffix: rawConfig.querySuffix || defaultSuffix,
mutationSuffix: rawConfig.mutationSuffix || defaultSuffix,
subscriptionSuffix: rawConfig.subscriptionSuffix || defaultSuffix,
scalars: buildScalars(schema, rawConfig.scalars, C_SHARP_SCALARS),
scalars: buildScalarsFromConfig(schema, rawConfig, C_SHARP_SCALARS),
typesafeOperation: rawConfig.typesafeOperation || false,
},
documents
Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/c-sharp/c-sharp/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
EnumValuesMap,
indentMultiline,
indent,
buildScalars,
getBaseTypeNode,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import { CSharpResolversPluginRawConfig } from './config';
import {
Expand Down Expand Up @@ -58,7 +58,7 @@ export class CSharpResolversVisitor extends BaseVisitor<CSharpResolversPluginRaw
namespaceName: rawConfig.namespaceName || 'GraphQLCodeGen',
className: rawConfig.className || 'Types',
emitRecords: rawConfig.emitRecords || false,
scalars: buildScalars(_schema, rawConfig.scalars, C_SHARP_SCALARS),
scalars: buildScalarsFromConfig(_schema, rawConfig, C_SHARP_SCALARS),
});
}

Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/java/java/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
EnumValuesMap,
indentMultiline,
indent,
buildScalars,
getBaseTypeNode,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import { JavaResolversPluginRawConfig } from './config';
import {
Expand Down Expand Up @@ -44,7 +44,7 @@ export class JavaResolversVisitor extends BaseVisitor<JavaResolversPluginRawConf
className: rawConfig.className || 'Types',
classMembersPrefix: rawConfig.classMembersPrefix || '',
package: rawConfig.package || defaultPackageName,
scalars: buildScalars(_schema, rawConfig.scalars, JAVA_SCALARS, 'Object'),
scalars: buildScalarsFromConfig(_schema, rawConfig, JAVA_SCALARS, 'Object'),
});
}

Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/java/kotlin/src/visitor.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
BaseVisitor,
buildScalars,
EnumValuesMap,
indent,
indentMultiline,
ParsedConfig,
transformComment,
getBaseTypeNode,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import { KotlinResolversPluginRawConfig } from './config';
import {
Expand Down Expand Up @@ -54,7 +54,7 @@ export class KotlinResolversVisitor extends BaseVisitor<KotlinResolversPluginRaw
listType: rawConfig.listType || 'Iterable',
withTypes: rawConfig.withTypes || false,
package: rawConfig.package || defaultPackageName,
scalars: buildScalars(_schema, rawConfig.scalars, KOTLIN_SCALARS),
scalars: buildScalarsFromConfig(_schema, rawConfig, KOTLIN_SCALARS),
});
}

Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/java/resolvers/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
indent,
indentMultiline,
getBaseTypeNode,
buildScalars,
ExternalParsedMapper,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import { JavaResolversPluginRawConfig } from './config';
import { JAVA_SCALARS, JavaDeclarationBlock, wrapTypeWithModifiers } from '@graphql-codegen/java-common';
Expand Down Expand Up @@ -39,7 +39,7 @@ export class JavaResolversVisitor extends BaseVisitor<JavaResolversPluginRawConf
defaultMapper: parseMapper(rawConfig.defaultMapper || 'Object'),
className: rawConfig.className || 'Resolvers',
listType: rawConfig.listType || 'Iterable',
scalars: buildScalars(_schema, rawConfig.scalars, JAVA_SCALARS, 'Object'),
scalars: buildScalarsFromConfig(_schema, rawConfig, JAVA_SCALARS, 'Object'),
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NormalizedScalarsMap } from './types';
import autoBind from 'auto-bind';
import { DEFAULT_SCALARS } from './scalars';
import { DeclarationBlock, DeclarationBlockConfig, buildScalars, getConfigValue } from './utils';
import { DeclarationBlock, DeclarationBlockConfig, getConfigValue, buildScalarsFromConfig } from './utils';
import {
GraphQLSchema,
FragmentDefinitionNode,
Expand Down Expand Up @@ -136,7 +136,7 @@ export class BaseDocumentsVisitor<
addTypename: !rawConfig.skipTypename,
globalNamespace: !!rawConfig.globalNamespace,
operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''),
scalars: buildScalars(_schema, rawConfig.scalars, defaultScalars),
scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
...((additionalConfig || {}) as any),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import {
DeclarationBlockConfig,
indent,
getBaseTypeNode,
buildScalars,
getConfigValue,
getRootTypeNames,
stripMapperTypeInterpolation,
OMIT_TYPE,
REQUIRE_FIELDS_TYPE,
wrapTypeWithModifiers,
buildScalarsFromConfig,
} from './utils';
import {
NameNode,
Expand Down Expand Up @@ -385,7 +385,7 @@ export class BaseResolversVisitor<
? parseMapper(rawConfig.defaultMapper || 'any', 'DefaultMapperType')
: null,
mappers: transformMappers(rawConfig.mappers || {}, rawConfig.mapperTypeSuffix),
scalars: buildScalars(_schema, rawConfig.scalars, defaultScalars),
scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
internalResolversPrefix: getConfigValue(rawConfig.internalResolversPrefix, '__'),
...(additionalConfig || {}),
} as TPluginConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ import {
} from './types';
import {
transformComment,
buildScalars,
DeclarationBlock,
DeclarationBlockConfig,
indent,
wrapWithSingleQuotes,
getConfigValue,
buildScalarsFromConfig,
} from './utils';
import { OperationVariablesToObject } from './variables-to-object';
import { parseEnumValues } from './enum-values';
Expand Down Expand Up @@ -215,7 +215,7 @@ export class BaseTypesVisitor<
ignoreEnumValuesFromSchema: rawConfig.ignoreEnumValuesFromSchema,
}),
declarationKind: normalizeDeclarationKind(rawConfig.declarationKind),
scalars: buildScalars(_schema, rawConfig.scalars, defaultScalars),
scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
fieldWrapperValue: getConfigValue(rawConfig.fieldWrapperValue, 'T'),
wrapFieldDefinitions: getConfigValue(rawConfig.wrapFieldDefinitions, false),
ignoreEnumValuesFromSchema: getConfigValue(rawConfig.ignoreEnumValuesFromSchema, false),
Expand Down
25 changes: 25 additions & 0 deletions packages/plugins/other/visitor-plugin-common/src/base-visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@ export interface ParsedConfig {
}

export interface RawConfig {
/**
* @description Makes scalars strict.
*
* If scalars are found in the schema that are not defined in `scalars`
* an error will be thrown during codegen.
* @default false
*
* @exampleMarkdown
* ```yml
* config:
* strictScalars: true
* ```
*/
strictScalars?: boolean;
/**
* @description Allows you to override the type that unknown scalars will have.
* @default any
*
* @exampleMarkdown
* ```yml
* config:
* defaultScalarType: unknown
* ```
*/
defaultScalarType?: string;
/**
* @description Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import {
import { DepGraph } from 'dependency-graph';
import gqlTag from 'graphql-tag';
import { Types } from '@graphql-codegen/plugin-helpers';
import { getConfigValue, buildScalars } from './utils';
import { getConfigValue, buildScalarsFromConfig } from './utils';
import { LoadedFragment, ParsedImport } from './types';
import { basename, extname } from 'path';
import { DEFAULT_SCALARS } from './scalars';
import { pascalCase } from 'change-case-all';
import { generateFragmentImportStatement } from './imports';
import { optimizeDocumentNode } from '@graphql-tools/optimize';
Expand Down Expand Up @@ -197,7 +196,7 @@ export class ClientSideBaseVisitor<
documents?: Types.DocumentFile[]
) {
super(rawConfig, {
scalars: buildScalars(_schema, rawConfig.scalars, DEFAULT_SCALARS),
scalars: buildScalarsFromConfig(_schema, rawConfig),
dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false),
optimizeDocumentNode: getConfigValue(rawConfig.optimizeDocumentNode, true),
omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false),
Expand Down
20 changes: 19 additions & 1 deletion packages/plugins/other/visitor-plugin-common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
import { ScalarsMap, NormalizedScalarsMap, ParsedScalarsMap } from './types';
import { DEFAULT_SCALARS } from './scalars';
import { parseMapper } from './mappers';
import { RawConfig } from './base-visitor';

export const getConfigValue = <T = any>(value: T, defaultValue: T): T => {
if (value === null || value === undefined) {
Expand Down Expand Up @@ -260,11 +261,25 @@ export function convertNameParts(str: string, func: (str: string) => string, rem
.join('_');
}

export function buildScalarsFromConfig(
schema: GraphQLSchema | undefined,
config: RawConfig,
defaultScalarsMapping: NormalizedScalarsMap = DEFAULT_SCALARS,
defaultScalarType = 'any'
): ParsedScalarsMap {
return buildScalars(
schema,
config.scalars,
defaultScalarsMapping,
config.strictScalars ? null : config.defaultScalarType || defaultScalarType
);
}

export function buildScalars(
schema: GraphQLSchema | undefined,
scalarsMapping: ScalarsMap,
defaultScalarsMapping: NormalizedScalarsMap = DEFAULT_SCALARS,
defaultScalarType = 'any'
defaultScalarType: string | null = 'any'
): ParsedScalarsMap {
const result: ParsedScalarsMap = {};

Expand Down Expand Up @@ -292,6 +307,9 @@ export function buildScalars(
type: JSON.stringify(scalarsMapping[name]),
};
} else if (!defaultScalarsMapping[name]) {
if (defaultScalarType === null) {
throw new Error(`Unknown scalar type ${name}. Please override it using the "scalars" configuration field!`);
}
result[name] = {
isExternal: false,
type: defaultScalarType,
Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/typescript/compatibility/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
DeclarationBlock,
indent,
getConfigValue,
buildScalars,
ParsedConfig,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import { GraphQLSchema, OperationDefinitionNode, OperationTypeNode, FragmentDefinitionNode } from 'graphql';

Expand All @@ -26,7 +26,7 @@ export class CompatibilityPluginVisitor extends BaseVisitor<CompatibilityPluginR
noNamespaces: getConfigValue<boolean>(rawConfig.noNamespaces, false),
preResolveTypes: getConfigValue<boolean>(rawConfig.preResolveTypes, false),
strict: getConfigValue<boolean>(rawConfig.strict, false),
scalars: buildScalars(_schema, rawConfig.scalars),
scalars: buildScalarsFromConfig(_schema, rawConfig),
} as any);
}

Expand Down
5 changes: 2 additions & 3 deletions packages/plugins/typescript/mongodb/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {
getConfigValue,
ParsedConfig,
BaseVisitor,
buildScalars,
DEFAULT_SCALARS,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import autoBind from 'auto-bind';
import { Directives, TypeScriptMongoPluginConfig } from './config';
Expand Down Expand Up @@ -64,7 +63,7 @@ export class TsMongoVisitor extends BaseVisitor<TypeScriptMongoPluginConfig, Typ
idFieldName: pluginConfig.idFieldName || '_id',
enumsAsString: getConfigValue<boolean>(pluginConfig.enumsAsString, true),
avoidOptionals: getConfigValue<boolean>(pluginConfig.avoidOptionals, false),
scalars: buildScalars(_schema, pluginConfig.scalars, DEFAULT_SCALARS),
scalars: buildScalarsFromConfig(_schema, pluginConfig),
} as Partial<TypeScriptMongoPluginParsedConfig>) as any);
autoBind(this);
}
Expand Down
48 changes: 48 additions & 0 deletions packages/plugins/typescript/typescript/tests/typescript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1797,6 +1797,54 @@ describe('TypeScript', () => {
validateTs(result);
});

it('Should correctly throw an error when an unknown scalar is detected while using `strictScalars`', () => {
const schema = buildSchema(`
scalar MyScalar
type MyType {
foo: String
bar: MyScalar!
}`);

expect(() => {
plugin(schema, [], { strictScalars: true }, { outputFile: '' });
}).toThrow('Unknown scalar type MyScalar');
});

it('Should allow overriding default scalar type', async () => {
const schema = buildSchema(`
scalar MyScalar
type MyType {
foo: String
bar: MyScalar!
}`);
const result = (await plugin(
schema,
[],
{ defaultScalarType: 'unknown' },
{ outputFile: '' }
)) as Types.ComplexPluginOutput;

expect(result.content).toBeSimilarStringTo(`
export type Scalars = {
ID: string;
String: string;
Boolean: boolean;
Int: number;
Float: number;
MyScalar: unknown;
};`);

expect(result.content).toBeSimilarStringTo(`
export type MyType = {
__typename?: 'MyType';
foo?: Maybe<Scalars['String']>;
bar: Scalars['MyScalar'];
};`);
validateTs(result);
});

it('Should add FieldWrapper when field definition wrapping is enabled', async () => {
const schema = buildSchema(`
scalar A
Expand Down
4 changes: 2 additions & 2 deletions packages/presets/near-operation-file/src/fragment-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Types } from '@graphql-codegen/plugin-helpers';
import {
BaseVisitor,
buildScalars,
FragmentImport,
getConfigValue,
getPossibleTypes,
LoadedFragment,
ParsedConfig,
RawConfig,
ImportDeclaration,
buildScalarsFromConfig,
} from '@graphql-codegen/visitor-plugin-common';
import { DocumentNode, FragmentDefinitionNode, GraphQLSchema, Kind, print } from 'graphql';
import { DocumentImportResolverOptions } from './resolve-document-imports';
Expand Down Expand Up @@ -40,7 +40,7 @@ function buildFragmentRegistry(
schemaObject: GraphQLSchema
): FragmentRegistry {
const baseVisitor = new BaseVisitor<RawConfig, NearOperationFileParsedConfig>(config, {
scalars: buildScalars(schemaObject, config.scalars),
scalars: buildScalarsFromConfig(schemaObject, config),
dedupeOperationSuffix: getConfigValue(config.dedupeOperationSuffix, false),
omitOperationSuffix: getConfigValue(config.omitOperationSuffix, false),
fragmentVariablePrefix: getConfigValue(config.fragmentVariablePrefix, ''),
Expand Down

0 comments on commit 097bea2

Please sign in to comment.