diff --git a/dev-test/test/codegen.yml b/dev-test/test/codegen.yml deleted file mode 100644 index 9fb6e02677f..00000000000 --- a/dev-test/test/codegen.yml +++ /dev/null @@ -1,20 +0,0 @@ - -schema: - - 'schema.graphql' -documents: - - './src/**/*.graphql' -config: - namingConvention: change-case#pascalCase - withHooks: true -generates: - src/gql/__generated__/types.ts: - - 'typescript' - src/: - preset: near-operation-file - presetConfig: - extension: .generated.tsx - baseTypesPath: gql/__generated__/types.ts - plugins: - - add: /* eslint-disable */ - - typescript-operations - - typescript-react-apollo diff --git a/dev-test/test/schema.graphql b/dev-test/test/schema.graphql deleted file mode 100644 index c3f2a8229ef..00000000000 --- a/dev-test/test/schema.graphql +++ /dev/null @@ -1,23 +0,0 @@ - -type TypeB { - param1: String - param2: String -} - -type TypeA { - field1: String - field2: String - field3: String - field4: String - field5: String - field6: String - field7: TypeB -} - -type Query { - things: TypeA! -} - -schema { - query: Query -} \ No newline at end of file diff --git a/dev-test/test/src/ComponentA/document.generated.tsx b/dev-test/test/src/ComponentA/document.generated.tsx deleted file mode 100644 index d3e1eb30c74..00000000000 --- a/dev-test/test/src/ComponentA/document.generated.tsx +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable */ -import * as Types from '../gql/__generated__/types'; - -import gql from 'graphql-tag'; -export type ComponentA_TypeAFragment = { __typename?: 'TypeA' } & Pick; -export const ComponentA_TypeAFragmentDoc = gql` - fragment ComponentA_TypeA on TypeA { - field1 - } -`; diff --git a/dev-test/test/src/ComponentA/document.graphql b/dev-test/test/src/ComponentA/document.graphql deleted file mode 100644 index 040084cfb21..00000000000 --- a/dev-test/test/src/ComponentA/document.graphql +++ /dev/null @@ -1,3 +0,0 @@ -fragment ComponentA_TypeA on TypeA { - field1 -} diff --git a/dev-test/test/src/ComponentB/document.generated.tsx b/dev-test/test/src/ComponentB/document.generated.tsx deleted file mode 100644 index 065227fa9af..00000000000 --- a/dev-test/test/src/ComponentB/document.generated.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable */ -import * as Types from '../gql/__generated__/types'; - -import gql from 'graphql-tag'; -export type ComponentB_TypeBFragment = { __typename?: 'TypeB' } & Pick; - -export type ComponentB_TypeAFragment = { __typename?: 'TypeA' } & Pick & { field7: Types.Maybe<{ __typename?: 'TypeB' } & ComponentB_TypeBFragment> }; -export const ComponentB_TypeBFragmentDoc = gql` - fragment ComponentB_TypeB on TypeB { - param1 - param2 - } -`; -export const ComponentB_TypeAFragmentDoc = gql` - fragment ComponentB_TypeA on TypeA { - field3 - field4 - field5 - field6 - field7 { - ...ComponentB_TypeB - } - } - ${ComponentB_TypeBFragmentDoc} -`; diff --git a/dev-test/test/src/ComponentB/document.graphql b/dev-test/test/src/ComponentB/document.graphql deleted file mode 100644 index d68468f87d7..00000000000 --- a/dev-test/test/src/ComponentB/document.graphql +++ /dev/null @@ -1,14 +0,0 @@ -fragment ComponentB_TypeB on TypeB { - param1 - param2 -} - -fragment ComponentB_TypeA on TypeA { - field3 - field4 - field5 - field6 - field7 { - ...ComponentB_TypeB - } -} diff --git a/dev-test/test/src/document.generated.tsx b/dev-test/test/src/document.generated.tsx deleted file mode 100644 index 50c5e234abe..00000000000 --- a/dev-test/test/src/document.generated.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* eslint-disable */ -import * as Types from './gql/__generated__/types'; - -import { ComponentB_TypeAFragment } from './ComponentB/document.generated'; -import { ComponentA_TypeAFragment } from './ComponentA/document.generated'; -import gql from 'graphql-tag'; -import { ComponentA_TypeAFragmentDoc } from './ComponentA/document.generated'; -import { ComponentB_TypeAFragmentDoc } from './ComponentB/document.generated'; -import * as React from 'react'; -import * as ReactApollo from 'react-apollo'; -import * as ReactApolloHooks from 'react-apollo-hooks'; -export type Omit = Pick>; -export type ComponentC_FetchThingsQueryVariables = {}; - -export type ComponentC_FetchThingsQuery = { __typename?: 'Query' } & { things: { __typename?: 'TypeA' } & ComponentC_TypeAFragment }; - -export type ComponentC_TypeAFragment = { __typename?: 'TypeA' } & (ComponentA_TypeAFragment & ComponentB_TypeAFragment); -export const ComponentC_TypeAFragmentDoc = gql` - fragment ComponentC_TypeA on TypeA { - ...ComponentA_TypeA - ...ComponentB_TypeA - } - ${ComponentA_TypeAFragmentDoc} - ${ComponentB_TypeAFragmentDoc} -`; -export const ComponentC_FetchThingsDocument = gql` - query ComponentC_FetchThings { - things { - ...ComponentC_TypeA - } - } - ${ComponentC_TypeAFragmentDoc} -`; -export type ComponentC_FetchThingsComponentProps = Omit, 'query'>; - -export const ComponentC_FetchThingsComponent = (props: ComponentC_FetchThingsComponentProps) => query={ComponentC_FetchThingsDocument} {...props} />; - -export type ComponentC_FetchThingsProps = Partial> & TChildProps; -export function withComponentC_FetchThings(operationOptions?: ReactApollo.OperationOption>) { - return ReactApollo.withQuery>(ComponentC_FetchThingsDocument, { - alias: 'withComponentC_FetchThings', - ...operationOptions, - }); -} - -export function useComponentC_FetchThingsQuery(baseOptions?: ReactApolloHooks.QueryHookOptions) { - return ReactApolloHooks.useQuery(ComponentC_FetchThingsDocument, baseOptions); -} diff --git a/dev-test/test/src/document.graphql b/dev-test/test/src/document.graphql deleted file mode 100644 index b4d1b8ab7cf..00000000000 --- a/dev-test/test/src/document.graphql +++ /dev/null @@ -1,12 +0,0 @@ -query ComponentC_FetchThings { - things { - ...ComponentC_TypeA # We're using it before declare - # Causing self imports and then duplicate declare - } -} - -fragment ComponentC_TypeA on TypeA { - ...ComponentA_TypeA - ...ComponentB_TypeA # Fragments that this fragment is - # uses are getting imported with no usage. -} \ No newline at end of file diff --git a/dev-test/test/src/gql/__generated__/types.ts b/dev-test/test/src/gql/__generated__/types.ts deleted file mode 100644 index 4a67e93b344..00000000000 --- a/dev-test/test/src/gql/__generated__/types.ts +++ /dev/null @@ -1,31 +0,0 @@ -export type Maybe = T | null; -/** All built-in and custom scalars, mapped to their actual values */ -export type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: number; -}; - -export type Query = { - __typename?: 'Query'; - things: TypeA; -}; - -export type TypeA = { - __typename?: 'TypeA'; - field1?: Maybe; - field2?: Maybe; - field3?: Maybe; - field4?: Maybe; - field5?: Maybe; - field6?: Maybe; - field7?: Maybe; -}; - -export type TypeB = { - __typename?: 'TypeB'; - param1?: Maybe; - param2?: Maybe; -}; diff --git a/docs/getting-started/programmatic-usage.md b/docs/getting-started/programmatic-usage.md index 1090db0b58c..ca2d8b2e4df 100644 --- a/docs/getting-started/programmatic-usage.md +++ b/docs/getting-started/programmatic-usage.md @@ -54,4 +54,4 @@ fs.writeFile(path.join(__dirname, outputFile), output, () => { }); ``` -> We are using this API in the live demo in GraphQL Code Generator website, [here is the code](https://github.com/dotansimha/graphql-code-generator/blob/master/website/live-demo/src/App.js#L79). +> We are using this API in the live demo in GraphQL Code Generator website, [here is the code](https://github.com/dotansimha/graphql-code-generator/blob/master/website/live-demo/src/generate.ts). diff --git a/lerna.json b/lerna.json index 4a6f0776b5c..56dd2559c7f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,6 @@ { "version": "1.3.1", "npmClient": "yarn", - "useWorkspaces": true + "useWorkspaces": true, + "concurrency": 2 } diff --git a/package.json b/package.json index 0823fc5d83d..e75112b2785 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "jest": "24.8.0", "jest-junit": "6.4.0", "lerna": "3.15.0", - "lint-staged": "9.0.2", + "lint-staged": "9.1.0", "microbundle": "0.11.0", "react-apollo": "2.5.8", "react-apollo-hooks": "0.4.5", diff --git a/packages/graphql-codegen-cli/package.json b/packages/graphql-codegen-cli/package.json index c23c2a34cf6..de3a881af9e 100644 --- a/packages/graphql-codegen-cli/package.json +++ b/packages/graphql-codegen-cli/package.json @@ -52,7 +52,7 @@ "babylon": "7.0.0-beta.47", "chalk": "2.4.2", "change-case": "3.1.0", - "chokidar": "3.0.1", + "chokidar": "3.0.2", "commander": "2.20.0", "common-tags": "1.8.0", "detect-indent": "6.0.0", diff --git a/packages/graphql-codegen-cli/src/codegen.ts b/packages/graphql-codegen-cli/src/codegen.ts index 04fbe7ddb7f..03d94549bc3 100644 --- a/packages/graphql-codegen-cli/src/codegen.ts +++ b/packages/graphql-codegen-cli/src/codegen.ts @@ -5,10 +5,11 @@ import { normalizeOutputParam, normalizeInstanceOrArray, normalizeConfig } from import { prettify } from './utils/prettier'; import { Renderer } from './utils/listr-renderer'; import { loadSchema, loadDocuments } from './load'; -import { GraphQLError, DocumentNode, buildASTSchema } from 'graphql'; +import { GraphQLError, DocumentNode } from 'graphql'; import { getPluginByName } from './plugins'; import { getPresetByName } from './presets'; import { debugLog } from './utils/debugging'; +import { tryToBuildSchema } from './utils/try-to-build-schema'; export const defaultLoader = (mod: string) => import(mod); @@ -214,6 +215,7 @@ export async function executeCodegen(config: Types.Config): Promise = $Diff & $ObjMapi(k: Key) => $NonMaybeType<$ElementType>>;`; diff --git a/packages/plugins/flow/resolvers/src/index.ts b/packages/plugins/flow/resolvers/src/index.ts index a7743f8a0f2..489c13c5b54 100644 --- a/packages/plugins/flow/resolvers/src/index.ts +++ b/packages/plugins/flow/resolvers/src/index.ts @@ -83,7 +83,7 @@ ${resolverTypeWrapper} } return { - prepend: [gqlImports, ...mappersImports], + prepend: [gqlImports, ...mappersImports, ...visitor.globalDeclarations], content: [header, resolversTypeMapping, resolversParentTypeMapping, ...visitorResult.definitions.filter(d => typeof d === 'string'), getRootResolver(), getAllDirectiveResolvers()].join('\n'), }; }; diff --git a/packages/plugins/flow/resolvers/src/visitor.ts b/packages/plugins/flow/resolvers/src/visitor.ts index 93a543b1100..473c84fa478 100644 --- a/packages/plugins/flow/resolvers/src/visitor.ts +++ b/packages/plugins/flow/resolvers/src/visitor.ts @@ -1,8 +1,9 @@ import { FlowResolversPluginConfig } from './index'; -import { ListTypeNode, NamedTypeNode, NonNullTypeNode, GraphQLSchema, ScalarTypeDefinitionNode } from 'graphql'; +import { ListTypeNode, NamedTypeNode, NonNullTypeNode, GraphQLSchema, ScalarTypeDefinitionNode, InputValueDefinitionNode } from 'graphql'; import * as autoBind from 'auto-bind'; import { indent, ParsedResolversConfig, BaseResolversVisitor, DeclarationBlock } from '@graphql-codegen/visitor-plugin-common'; import { FlowOperationVariablesToObject } from '@graphql-codegen/flow'; +import { FLOW_REQUIRE_FIELDS_TYPE } from './flow-util-types'; export interface ParsedFlorResolversConfig extends ParsedResolversConfig {} @@ -17,6 +18,11 @@ export class FlowResolversVisitor extends BaseResolversVisitor`; } + protected applyRequireFields(argsType: string, fields: InputValueDefinitionNode[]): string { + this._globalDeclarations.add(FLOW_REQUIRE_FIELDS_TYPE); + return `$RequireFields<${argsType}, { ${fields.map(f => `${f.name.value}: *`).join(', ')} }>`; + } + protected buildMapperImport(source: string, types: { identifier: string; asDefault?: boolean }[]): string { if (types[0] && types[0].asDefault) { return `import type ${types[0].identifier} from '${source}';`; diff --git a/packages/plugins/flow/resolvers/tests/flow-resolvers.spec.ts b/packages/plugins/flow/resolvers/tests/flow-resolvers.spec.ts index 354c528ebe0..e8e82f96401 100644 --- a/packages/plugins/flow/resolvers/tests/flow-resolvers.spec.ts +++ b/packages/plugins/flow/resolvers/tests/flow-resolvers.spec.ts @@ -11,8 +11,22 @@ describe('Flow Resolvers Plugin', () => { expect(result).toMatchSnapshot(); }); + it('Default values of args and compatibility with typescript plugin', async () => { + const testSchema = buildSchema(/* GraphQL */ ` + type Query { + something(arg: String = "default_value"): String + } + `); + + const config: any = { noSchemaStitching: true }; + const result = (await plugin(testSchema, [], config, { outputFile: '' })) as Types.ComplexPluginOutput; + + expect(result.prepend).toContain(`export type $RequireFields = $Diff & $ObjMapi(k: Key) => $NonMaybeType<$ElementType>>;`); + expect(result.content).toContain(`something?: Resolver, ParentType, ContextType, $RequireFields>,`); + }); + it('Should generate ResolversParentTypes', () => { - const result = plugin(schema, [], {}, { outputFile: '' }); + const result = plugin(schema, [], {}, { outputFile: '' }) as Types.ComplexPluginOutput; expect(result.content).toBeSimilarStringTo(` /** Mapping between all available schema types and the resolvers parents */ @@ -72,7 +86,7 @@ describe('Flow Resolvers Plugin', () => { { rootValueType: 'MyRoot', asyncResolverTypes: true, - }, + } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; diff --git a/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts index dea1686dd95..e66d3740901 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts @@ -1,8 +1,8 @@ import { ParsedConfig, RawConfig, BaseVisitor } from './base-visitor'; import * as autoBind from 'auto-bind'; import { DEFAULT_SCALARS } from './scalars'; -import { ScalarsMap } from './types'; -import { DeclarationBlock, DeclarationBlockConfig, indent, getBaseTypeNode, buildScalars, getConfigValue, getBaseType, getRootTypeNames, stripMapperTypeInterpolation } from './utils'; +import { ScalarsMap, EnumValuesMap, ParsedEnumValuesMap } from './types'; +import { DeclarationBlock, DeclarationBlockConfig, indent, getBaseTypeNode, buildScalars, getConfigValue, getBaseType, getRootTypeNames, stripMapperTypeInterpolation, OMIT_TYPE, REQUIRE_FIELDS_TYPE } from './utils'; import { NameNode, ListTypeNode, @@ -21,10 +21,12 @@ import { isUnionType, GraphQLNamedType, GraphQLInterfaceType, + isEnumType, } from 'graphql'; import { DirectiveDefinitionNode, GraphQLObjectType, InputValueDefinitionNode, GraphQLOutputType } from 'graphql'; import { OperationVariablesToObject } from './variables-to-object'; import { ParsedMapper, parseMapper, transformMappers } from './mappers'; +import { parseEnumValues } from './enum-values'; export interface ParsedResolversConfig extends ParsedConfig { contextType: ParsedMapper; @@ -34,9 +36,24 @@ export interface ParsedResolversConfig extends ParsedConfig { }; defaultMapper: ParsedMapper | null; avoidOptionals: boolean; + addUnderscoreToArgsType: boolean; + enumValues: ParsedEnumValuesMap; } export interface RawResolversConfig extends RawConfig { + /** + * @name addUnderscoreToArgsType + * @type boolean + * @description Adds `_` to generated `Args` types in order to avoid duplicate identifiers. + * + * @example With Custom Values + * ```yml + * config: + * addUnderscoreToArgsType: true + * ``` + * + */ + addUnderscoreToArgsType?: boolean; /** * @name contextType * @type string @@ -165,6 +182,15 @@ export interface RawResolversConfig extends RawConfig { * ``` */ showUnusedMappers?: boolean; + /** + * @name enumValues + * @type EnumValuesMap + * @description Overrides the default value of enum values declared in your GraphQL schema, supported + * in this plugin because of the need for integeration with `typescript` package. + * See documentation under `typescript` plugin for more information and examples. + * + */ + enumValues?: EnumValuesMap; } export type ResolverTypes = { [gqlType: string]: string }; @@ -180,11 +206,14 @@ export class BaseResolversVisitor = new Set(); constructor(rawConfig: TRawConfig, additionalConfig: TPluginConfig, private _schema: GraphQLSchema, defaultScalars: ScalarsMap = DEFAULT_SCALARS) { super( rawConfig, { + enumValues: parseEnumValues(_schema, rawConfig.enumValues), + addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false), contextType: parseMapper(rawConfig.contextType || 'any', 'ContextType'), rootValueType: parseMapper(rawConfig.rootValueType || '{}', 'RootValueType'), avoidOptionals: getConfigValue(rawConfig.avoidOptionals, false), @@ -275,6 +304,8 @@ export class BaseResolversVisitor `'${f.fieldName}'`).join(' | ')}> & { ${relevantFields.map(f => `${f.fieldName}${f.addOptionalSign ? '?' : ''}: ${f.replaceWithType}`).join(', ')} }`; } @@ -425,6 +457,10 @@ export class BaseResolversVisitor !this._usedMappers[name]); } + public get globalDeclarations(): string[] { + return Array.from(this._globalDeclarations); + } + public get mappersImports(): string[] { const groupedMappers: { [sourceFile: string]: { identifier: string; asDefault?: boolean }[] } = {}; @@ -602,30 +638,41 @@ export type IDirectiveResolvers${contextType} = ${name};` const hasArguments = node.arguments && node.arguments.length > 0; return (parentName: string) => { - const original = parent[key]; + const original: FieldDefinitionNode = parent[key]; const baseType = getBaseTypeNode(original.type); const realType = baseType.name.value; const typeToUse = this.getTypeToUse(realType); const mappedType = this._variablesTransfomer.wrapAstTypeWithModifiers(typeToUse, original.type); const subscriptionType = this._schema.getSubscriptionType(); const isSubscriptionType = subscriptionType && subscriptionType.name === parentName; + let argsType = hasArguments + ? `${this.convertName(parentName, { + useTypesPrefix: true, + }) + + (this.config.addUnderscoreToArgsType ? '_' : '') + + this.convertName(node.name, { + useTypesPrefix: false, + }) + + 'Args'}` + : null; + + if (argsType !== null) { + const argsToForceRequire = original.arguments.filter(arg => !!arg.defaultValue); + + if (argsToForceRequire.length > 0) { + argsType = this.applyRequireFields(argsType, argsToForceRequire); + } + } - return indent( - `${node.name}${this.config.avoidOptionals ? '' : '?'}: ${isSubscriptionType ? 'SubscriptionResolver' : 'Resolver'}<${mappedType}, ParentType, ContextType${ - hasArguments - ? `, ${this.convertName(parentName, { - useTypesPrefix: true, - }) + - this.convertName(node.name, { - useTypesPrefix: false, - }) + - 'Args'}` - : '' - }>,` - ); + return indent(`${node.name}${this.config.avoidOptionals ? '' : '?'}: ${isSubscriptionType ? 'SubscriptionResolver' : 'Resolver'}<${mappedType}, ParentType, ContextType${argsType ? `, ${argsType}` : ''}>,`); }; } + protected applyRequireFields(argsType: string, fields: InputValueDefinitionNode[]): string { + this._globalDeclarations.add(REQUIRE_FIELDS_TYPE); + return `RequireFields<${argsType}, ${fields.map(f => `'${f.name.value}'`).join(', ')}>`; + } + ObjectTypeDefinition(node: ObjectTypeDefinitionNode) { const name = this.convertName(node, { suffix: 'Resolvers', diff --git a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts index 7082931627e..e08bfab0c18 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts @@ -15,23 +15,36 @@ import { ScalarTypeDefinitionNode, UnionTypeDefinitionNode, StringValueNode, - isUnionType, - isInterfaceType, } from 'graphql'; import { BaseVisitor, ParsedConfig, RawConfig } from './base-visitor'; import { parseMapper } from './mappers'; import { DEFAULT_SCALARS } from './scalars'; import { normalizeDeclarationKind } from './declaration-kinds'; -import { EnumValuesMap, ScalarsMap, DeclarationKindConfig, DeclarationKind } from './types'; -import { transformComment, buildScalars, DeclarationBlock, DeclarationBlockConfig, indent, wrapWithSingleQuotes } from './utils'; +import { EnumValuesMap, ScalarsMap, DeclarationKindConfig, DeclarationKind, ParsedEnumValuesMap } from './types'; +import { transformComment, buildScalars, DeclarationBlock, DeclarationBlockConfig, indent, wrapWithSingleQuotes, getConfigValue } from './utils'; import { OperationVariablesToObject } from './variables-to-object'; +import { parseEnumValues } from './enum-values'; export interface ParsedTypesConfig extends ParsedConfig { - enumValues: EnumValuesMap; + enumValues: ParsedEnumValuesMap; declarationKind: DeclarationKindConfig; + addUnderscoreToArgsType: boolean; } export interface RawTypesConfig extends RawConfig { + /** + * @name addUnderscoreToArgsType + * @type boolean + * @description Adds `_` to generated `Args` types in order to avoid duplicate identifiers. + * + * @example With Custom Values + * ```yml + * config: + * addUnderscoreToArgsType: true + * ``` + * + */ + addUnderscoreToArgsType?: boolean; /** * @name enumValues * @type EnumValuesMap @@ -52,6 +65,12 @@ export interface RawTypesConfig extends RawConfig { * enumValues: * MyEnum: ./my-file#MyCustomEnum * ``` + * + * @example Import All Enums from a file + * ```yml + * config: + * enumValues: ./my-file + * ``` */ enumValues?: EnumValuesMap; /** @@ -83,7 +102,8 @@ export class BaseTypesVisitor { const mappedValue = this.config.enumValues[enumName]; - if (mappedValue && typeof mappedValue === 'string') { - const mapper = parseMapper(mappedValue); - - if (mapper.isExternal) { - const identifier = mapper.type === enumName ? enumName : `${mapper.type} as ${enumName}`; + if (mappedValue.sourceFile) { + const identifier = mappedValue.sourceIdentifier !== mappedValue.typeIdentifier ? `${mappedValue.sourceIdentifier} as ${mappedValue.typeIdentifier}` : mappedValue.sourceIdentifier; - return this._buildEnumImport(identifier, mapper.source); - } + return this._buildEnumImport(identifier, mappedValue.sourceFile); } return null; @@ -244,7 +260,7 @@ export class BaseTypesVisitor { const name = node.name.value + + (this.config.addUnderscoreToArgsType ? '_' : '') + this.convertName(field, { useTypesPrefix: false, }) + @@ -311,6 +328,8 @@ export class BaseTypesVisitor isEnumType(allTypes[t])); + + if (typeof mapOrStr === 'object') { + const invalidMappings = Object.keys(mapOrStr).filter(gqlName => !allEnums.includes(gqlName)); + + if (invalidMappings.length > 0) { + throw new DetailedError(`Invalid 'enumValues' mapping!`, `The following types does not exist in your GraphQL schema: ${invalidMappings.join(', ')}`); + } + + return Object.keys(mapOrStr).reduce( + (prev, gqlIdentifier) => { + const pointer = mapOrStr[gqlIdentifier]; + + if (typeof pointer === 'string') { + const mapper = parseMapper(pointer, gqlIdentifier); + + return { + ...prev, + [gqlIdentifier]: { + typeIdentifier: gqlIdentifier, + sourceFile: mapper.source, + sourceIdentifier: mapper.type, + mappedValues: null, + }, + }; + } else if (typeof pointer === 'object') { + return { + ...prev, + [gqlIdentifier]: { + typeIdentifier: gqlIdentifier, + sourceFile: null, + sourceIdentifier: null, + mappedValues: pointer, + }, + }; + } else { + throw new DetailedError(`Invalid "enumValues" configuration`, `Enum "${gqlIdentifier}": expected string or object (with enum values mapping)`); + } + }, + {} as ParsedEnumValuesMap + ); + } else if (typeof mapOrStr === 'string') { + return allEnums.reduce( + (prev, enumName) => { + return { + ...prev, + [enumName]: { + typeIdentifier: enumName, + sourceFile: mapOrStr, + sourceIdentifier: enumName, + mappedValues: null, + }, + }; + }, + {} as ParsedEnumValuesMap + ); + } + + return {}; +} diff --git a/packages/plugins/other/visitor-plugin-common/src/types.ts b/packages/plugins/other/visitor-plugin-common/src/types.ts index 5080b51b6d7..89876b13edd 100644 --- a/packages/plugins/other/visitor-plugin-common/src/types.ts +++ b/packages/plugins/other/visitor-plugin-common/src/types.ts @@ -1,7 +1,8 @@ import { ASTNode, FragmentDefinitionNode } from 'graphql'; export type ScalarsMap = { [name: string]: string }; -export type EnumValuesMap = { [enumName: string]: string | ({ [key: string]: string } & AdditionalProps) }; +export type EnumValuesMap = string | { [enumName: string]: string | ({ [key: string]: string } & AdditionalProps) }; +export type ParsedEnumValuesMap = { [enumName: string]: { mappedValues?: { [valueName: string]: string }; typeIdentifier: string; sourceIdentifier?: string; sourceFile?: string } }; export type ConvertNameFn = ConvertFn; export interface ConvertOptions { diff --git a/packages/plugins/other/visitor-plugin-common/src/utils.ts b/packages/plugins/other/visitor-plugin-common/src/utils.ts index e7277913275..4eae242b916 100644 --- a/packages/plugins/other/visitor-plugin-common/src/utils.ts +++ b/packages/plugins/other/visitor-plugin-common/src/utils.ts @@ -273,3 +273,4 @@ export function stripMapperTypeInterpolation(identifier: string): string { } export const OMIT_TYPE = 'export type Omit = Pick>;'; +export const REQUIRE_FIELDS_TYPE = `export type RequireFields = { [X in Exclude]?: T[X] } & { [P in K]-?: NonNullable };`; diff --git a/packages/plugins/typescript/document-nodes/src/index.ts b/packages/plugins/typescript/document-nodes/src/index.ts index 465d8d758f1..efd981393f7 100644 --- a/packages/plugins/typescript/document-nodes/src/index.ts +++ b/packages/plugins/typescript/document-nodes/src/index.ts @@ -72,11 +72,37 @@ export interface TypeScriptDocumentNodesPluginConfig { * ``` */ nameSuffix?: string; + /** + * @name noGraphQLTag + * @type boolean + * @default false + * @description Instead of adding gql tag with the GraphQL operation, it uses + * the precompiled JSON representation (DocumentNode) of the operation. + * + * @example + * ```yml + * config: + * noGraphQLTag: true + * ``` + */ + noGraphQLTag?: boolean; transformUnderscore?: boolean; } +function _gql(operationDefinitionNode: OperationDefinitionNode, noGraphQLTag = false): string { + if (noGraphQLTag) { + const documentNode = { kind: 'Document', definitions: [operationDefinitionNode] }; + return JSON.stringify(documentNode, (k, v) => (k === 'loc' ? undefined : v), 2); + } else { + const code = print(operationDefinitionNode) + .replace(/^/gm, ' ') + .replace(/\s*$/, ''); + return ['gql`', code, '`'].join('\n'); + } +} + export const plugin: PluginFunction = (schema: GraphQLSchema, documents: Types.DocumentFile[], config: TypeScriptDocumentNodesPluginConfig): string => { - const { namingConvention, namePrefix = '', nameSuffix = '', transformUnderscore = false } = config; + const { namingConvention, namePrefix = '', nameSuffix = '', noGraphQLTag = false, transformUnderscore = false } = config; const convertFn = convertFactory({ namingConvention }); const content = documents .filter(documentFile => documentFile.filePath.length > 0) @@ -85,16 +111,21 @@ export const plugin: PluginFunction = (sche .filter((d: OperationDefinitionNode) => d.name && d.name.value) .map((d: OperationDefinitionNode) => { const name = convertFn(namePrefix + d.name.value + nameSuffix, { transformUnderscore }); - const code = print(d) - .replace(/^/gm, ' ') - .replace(/\s*$/, ''); - return ['export const ' + name + ': DocumentNode = gql`', code, '`;', ''].join('\n'); + return 'export const ' + name + ': DocumentNode = ' + _gql(d, noGraphQLTag) + ';\n'; }) .join('\n') ) .join('\n'); - const prepend = content ? [`import { DocumentNode } from 'graphql';`, `import gql from 'graphql-tag';`, '', ''] : []; + const prepend: string[] = []; + + if (content) { + prepend.push(`import { DocumentNode } from 'graphql';`); + if (!noGraphQLTag) { + prepend.push(`import gql from 'graphql-tag';`); + } + prepend.push('', ''); + } return prepend.join('\n') + content; }; diff --git a/packages/plugins/typescript/document-nodes/tests/graphql-document-nodes.spec.ts b/packages/plugins/typescript/document-nodes/tests/graphql-document-nodes.spec.ts index b4eb974d32f..59d39d8e054 100644 --- a/packages/plugins/typescript/document-nodes/tests/graphql-document-nodes.spec.ts +++ b/packages/plugins/typescript/document-nodes/tests/graphql-document-nodes.spec.ts @@ -320,4 +320,57 @@ describe('graphql-codegen typescript-graphql-document-nodes', () => { `); validateTs(result); }); + + it('Should generate simple module without graphql-tag', async () => { + const result = plugin( + null, + [ + { + filePath: 'some/file/my-query.graphql', + content: parse(/* GraphQL */ ` + query MyQuery { + field + } + `), + }, + ], + { noGraphQLTag: true }, + { outputFile: '' } + ) as string; + + expect(result).toBeSimilarStringTo(` + import { DocumentNode } from 'graphql'; + + export const MyQuery: DocumentNode = { + "kind": "Document", + "definitions": [ + { + "kind": "OperationDefinition", + "operation": "query", + "name": { + "kind": "Name", + "value": "MyQuery" + }, + "variableDefinitions": [], + "directives": [], + "selectionSet": { + "kind": "SelectionSet", + "selections": [ + { + "kind": "Field", + "name": { + "kind": "Name", + "value": "field" + }, + "arguments": [], + "directives": [] + } + ] + } + } + ] + }; + `); + validateTs(result); + }); }); diff --git a/packages/plugins/typescript/resolvers/src/index.ts b/packages/plugins/typescript/resolvers/src/index.ts index 72dc76518f7..8cce3053eac 100644 --- a/packages/plugins/typescript/resolvers/src/index.ts +++ b/packages/plugins/typescript/resolvers/src/index.ts @@ -1,4 +1,4 @@ -import { RawResolversConfig, OMIT_TYPE } from '@graphql-codegen/visitor-plugin-common'; +import { RawResolversConfig } from '@graphql-codegen/visitor-plugin-common'; import { Types, PluginFunction } from '@graphql-codegen/plugin-helpers'; import { isScalarType, parse, printSchema, visit, GraphQLSchema } from 'graphql'; import { TypeScriptResolversVisitor } from './visitor'; @@ -172,7 +172,7 @@ export type DirectiveResolverFn typeof d === 'string'), getRootResolver(), getAllDirectiveResolvers()].join('\n'), }; }; diff --git a/packages/plugins/typescript/resolvers/src/visitor.ts b/packages/plugins/typescript/resolvers/src/visitor.ts index 4cd92efabcb..11695f93242 100644 --- a/packages/plugins/typescript/resolvers/src/visitor.ts +++ b/packages/plugins/typescript/resolvers/src/visitor.ts @@ -1,7 +1,7 @@ import { TypeScriptResolversPluginConfig } from './index'; import { ListTypeNode, NamedTypeNode, NonNullTypeNode, GraphQLSchema } from 'graphql'; import * as autoBind from 'auto-bind'; -import { ParsedResolversConfig, BaseResolversVisitor } from '@graphql-codegen/visitor-plugin-common'; +import { ParsedResolversConfig, BaseResolversVisitor, getConfigValue } from '@graphql-codegen/visitor-plugin-common'; import { TypeScriptOperationVariablesToObject } from '@graphql-codegen/typescript'; export interface ParsedTypeScriptResolversConfig extends ParsedResolversConfig { @@ -15,10 +15,10 @@ export class TypeScriptResolversVisitor extends BaseResolversVisitor { await validate(result); }); + it('Default values of args and compatibility with typescript plugin', async () => { + const testSchema = buildSchema(/* GraphQL */ ` + type Query { + something(arg: String = "default_value"): String + } + `); + + const config: any = { noSchemaStitching: true }; + const result = (await plugin(testSchema, [], config, { outputFile: '' })) as Types.ComplexPluginOutput; + const mergedOutputs = mergeOutputs([ + result, + { + content: ` + const resolvers: QueryResolvers = { + something: (root, args, context, info) => { + return args.arg; // This should work becuase "args.arg" is now forced + } + };`, + }, + ]); + + expect(mergedOutputs).toContain(`export type RequireFields`); + expect(mergedOutputs).toContain(`something?: Resolver, ParentType, ContextType, RequireFields>,`); + validate(mergedOutputs); + }); + + it('Test for enum usage in resolvers (to verify compatibility with enumValues)', async () => { + const testSchema = buildSchema(/* GraphQL */ ` + type Query { + a: A + } + + enum A { + X + Y + Z + } + + enum NotMapped { + X + Y + } + + type B { + a: String + } + `); + + const config = { + enumValues: { + A: 'MyA', + }, + typesPrefix: 'GQL_', + }; + const result = (await plugin(testSchema, [], config, { outputFile: '' })) as Types.ComplexPluginOutput; + const tsContent = (await tsPlugin(testSchema, [], config, { outputFile: 'graphql.ts' })) as Types.ComplexPluginOutput; + const mergedOutputs = mergeOutputs([result, tsContent]); + + expect(mergedOutputs).toContain(`A: A,`); + expect(mergedOutputs).not.toContain(`A: GQL_A,`); + expect(mergedOutputs).toContain(`NotMapped: GQL_NotMapped,`); + expect(mergedOutputs).not.toContain(`NotMapped: NotMapped,`); + expect(mergedOutputs).toContain(`B: GQL_B,`); + }); + it('Should generate basic type resolvers', async () => { const result = (await plugin(schema, [], {}, { outputFile: '' })) as Types.ComplexPluginOutput; @@ -379,6 +444,22 @@ describe('TypeScript Resolvers Plugin', () => { await validate(mergeOutputs([result, `type MyCustomCtx = {};`])); }); + it('Should with correctly with addUnderscoreToArgsType set to true', async () => { + const result = (await plugin( + schema, + [], + { + addUnderscoreToArgsType: true, + }, + { outputFile: '' } + )) as Types.ComplexPluginOutput; + + expect(result.content).toContain('MyType_WithArgsArgs'); + expect(result.content).not.toContain('MyTypeWithArgsArgs'); + + await validate(mergeOutputs([result])); + }); + it('Should allow to override context with mapped context type', async () => { const result = (await plugin( schema, @@ -1017,7 +1098,7 @@ describe('TypeScript Resolvers Plugin', () => { { rootValueType: 'MyRoot', asyncResolverTypes: true, - }, + } as any, { outputFile: 'graphql.ts' } )) as Types.ComplexPluginOutput; diff --git a/packages/plugins/typescript/typescript/src/visitor.ts b/packages/plugins/typescript/typescript/src/visitor.ts index fb246d435ea..b6fcf542930 100644 --- a/packages/plugins/typescript/typescript/src/visitor.ts +++ b/packages/plugins/typescript/typescript/src/visitor.ts @@ -77,7 +77,7 @@ export class TsVisitor { }); describe('Issues', () => { + it('#2082 - Issues with enumValues and types prefix', async () => { + const testSchema = buildSchema(/* GraphQL */ ` + enum MyEnum { + A + B + C + } + + enum OtherEnum { + V + } + + type Test { + a: MyEnum + b: OtherEnum + } + `); + const result = (await plugin( + testSchema, + [], + { + typesPrefix: 'GQL_', + enumValues: { + MyEnum: './files#MyEnum', + }, + }, + { outputFile: '' } + )) as Types.ComplexPluginOutput; + expect(result.prepend).toContain(`import { MyEnum } from './files';`); + expect(result.content).toContain(`enum GQL_OtherEnum {`); + expect(result.content).toContain(`a?: Maybe,`); + expect(result.content).toContain(`b?: Maybe`); + }); + it('#1488 - Should generate readonly also in input types when immutableTypes is set', async () => { const schema = buildSchema(` input MyInput { @@ -260,6 +294,22 @@ describe('TypeScript', () => { };`); validateTs(result); }); + + it('#1954 - Duplicate type names for args type', async () => { + const schema = buildSchema(` + type PullRequest { + reviewThreads(first: Int!): Int + } + + type PullRequestReview { + threads(first: Int!, last: Int!): Int + }`); + + const result = (await plugin(schema, [], { addUnderscoreToArgsType: true }, { outputFile: '' })) as Types.ComplexPluginOutput; + + expect(result.content).toContain('PullRequest_ReviewThreadsArgs'); + expect(result.content).toContain('PullRequestReview_ThreadsArgs'); + }); }); describe('Config', () => { @@ -1511,6 +1561,18 @@ describe('TypeScript', () => { validateTs(result); }); + + it('Should imoprt all enums from a single file when specified as string', async () => { + const schema = buildSchema(`enum MyEnum { A, B, C } enum MyEnum2 { X, Y, Z }`); + const result = (await plugin(schema, [], { enumValues: './my-file' }, { outputFile: '' })) as Types.ComplexPluginOutput; + + expect(result.content).not.toContain(`export enum MyEnum`); + expect(result.content).not.toContain(`export enum MyEnum2`); + expect(result.prepend).toContain(`import { MyEnum } from './my-file';`); + expect(result.prepend).toContain(`import { MyEnum2 } from './my-file';`); + + validateTs(result); + }); }); it('should not have [object Object]', async () => { diff --git a/packages/presets/near-operation-file/src/index.ts b/packages/presets/near-operation-file/src/index.ts index ef415cf78a0..96a9496736a 100644 --- a/packages/presets/near-operation-file/src/index.ts +++ b/packages/presets/near-operation-file/src/index.ts @@ -3,7 +3,7 @@ import { BaseVisitor, LoadedFragment } from '@graphql-codegen/visitor-plugin-com import * as addPlugin from '@graphql-codegen/add'; import { join, resolve } from 'path'; import { Kind, FragmentDefinitionNode } from 'graphql'; -import { appendExtensionToFilePath, extractExternalFragmentsInUse, resolveRelativeImport } from './utils'; +import { appendExtensionToFilePath, extractExternalFragmentsInUse, resolveRelativeImport, isUsingTypes } from './utils'; export type NearOperationFileConfig = { /** @@ -158,7 +158,9 @@ export const preset: Types.OutputPreset = { } } - plugins.unshift({ add: `import * as ${importTypesNamespace} from '${relativeImportPath}';\n` }); + if (isUsingTypes(documentFile.content)) { + plugins.unshift({ add: `import * as ${importTypesNamespace} from '${relativeImportPath}';\n` }); + } return { filename: generatedFilePath, diff --git a/packages/presets/near-operation-file/src/utils.ts b/packages/presets/near-operation-file/src/utils.ts index 42bad3c3c46..c54f28820d1 100644 --- a/packages/presets/near-operation-file/src/utils.ts +++ b/packages/presets/near-operation-file/src/utils.ts @@ -1,5 +1,5 @@ import { parse, dirname, relative, join, isAbsolute } from 'path'; -import { DocumentNode, visit, FragmentSpreadNode, FragmentDefinitionNode } from 'graphql'; +import { DocumentNode, visit, FragmentSpreadNode, FragmentDefinitionNode, FieldNode } from 'graphql'; import { FragmentNameToFile } from './index'; export function appendExtensionToFilePath(baseFilePath: string, extension: string) { @@ -65,3 +65,21 @@ export function resolveRelativeImport(from: string, to: string): string { } return fixLocalFile(clearExtension(relative(dirname(from), to))); } + +export function isUsingTypes(document: DocumentNode): boolean { + let foundFields = 0; + + visit(document, { + enter: { + Field: (node: FieldNode) => { + const selections = node.selectionSet ? node.selectionSet.selections || [] : []; + + if (selections.length === 0) { + foundFields++; + } + }, + }, + }); + + return foundFields > 0; +} diff --git a/packages/presets/near-operation-file/tests/near-operation-file.spec.ts b/packages/presets/near-operation-file/tests/near-operation-file.spec.ts index ac56eb9ab56..6ca101a4fb8 100644 --- a/packages/presets/near-operation-file/tests/near-operation-file.spec.ts +++ b/packages/presets/near-operation-file/tests/near-operation-file.spec.ts @@ -22,6 +22,7 @@ describe('near-operation-file preset', () => { const operationAst = parse(/* GraphQL */ ` query { user { + id ...UserFields } } @@ -130,6 +131,35 @@ describe('near-operation-file preset', () => { expect(result.map(o => o.plugins)[0]).toEqual(expect.arrayContaining([{ add: `import * as Types from '../types';\n` }])); }); + it('Should NOT prepend the "add" plugin with Types import when selection set does not include direct fields', async () => { + const result = await preset.buildGeneratesSection({ + baseOutputDir: './src/', + config: {}, + presetConfig: { + cwd: '/some/deep/path', + baseTypesPath: 'types.ts', + }, + schema: schemaDocumentNode, + documents: [ + { + filePath: './test.graphql', + content: parse(/* GraphQL */ ` + query { + user { + ...UserFields + } + } + `), + }, + testDocuments[1], + ], + plugins: [{ typescript: {} }], + pluginMap: { typescript: {} as any }, + }); + + expect(result.map(o => o.plugins)[0]).not.toEqual(expect.arrayContaining([{ add: `import * as Types from '../types';\n` }])); + }); + it('Should prepend the "add" plugin with the correct import (long path)', async () => { const result = await preset.buildGeneratesSection({ baseOutputDir: './src/', diff --git a/website/live-demo/package.json b/website/live-demo/package.json index 16504100da3..1d8063d2f34 100644 --- a/website/live-demo/package.json +++ b/website/live-demo/package.json @@ -31,7 +31,7 @@ "@graphql-codegen/typescript-stencil-apollo": "1.3.1", "@graphql-codegen/typescript-urql": "1.3.1", "@graphql-codegen/website": "1.3.1", - "@material-ui/core": "4.1.3", + "@material-ui/core": "4.2.0", "@types/codemirror": "0.0.76", "@types/react": "16.8.23", "@types/react-dom": "16.8.4", diff --git a/website/live-demo/src/generate.ts b/website/live-demo/src/generate.ts index b026fcadc0c..faeef01a4ab 100644 --- a/website/live-demo/src/generate.ts +++ b/website/live-demo/src/generate.ts @@ -5,7 +5,8 @@ import { pluginLoaderMap } from './plugins'; export async function generate(config: string, schema: string, documents?: string): Promise { try { const cleanTabs = config.replace(/\t/g, ' '); - const { generates, ...rootConfig } = safeLoad(cleanTabs); + const { generates, ...otherFields } = safeLoad(cleanTabs); + const rootConfig = otherFields.config || {}; const filename = Object.keys(generates)[0]; const plugins = normalizeConfig(generates[filename].plugins || generates[filename]); const outputConfig = generates[filename].config; diff --git a/website/package.json b/website/package.json index cb8bac148d1..e6aa6599bd9 100644 --- a/website/package.json +++ b/website/package.json @@ -18,10 +18,10 @@ "@graphql-codegen/config-markdown-generator": "1.3.1", "babel-preset-minify": "0.5.0", "docusaurus": "1.11.1", - "netlify-lambda": "1.4.13", + "netlify-lambda": "1.5.0", "remarkable-embed": "0.4.1" }, "dependencies": { - "sendmail": "1.6.0" + "sendmail": "1.6.1" } } diff --git a/yarn.lock b/yarn.lock index ae7582922a6..874d4e36885 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1901,34 +1901,32 @@ npmlog "^4.1.2" write-file-atomic "^2.3.0" -"@material-ui/core@4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.1.3.tgz#0f8ffae88ac668399fbfc66efa1ed37c4ce29a7d" - integrity sha512-cSrI3yZ2L1XVi5IyO0/dPGUq1FaDBKTL9ygDOlvojD6bGuD/Qu17dCFAD8/mHV4CPNQMJYUKLYyOmqtDYdEB9g== +"@material-ui/core@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.2.0.tgz#fd57352c63a50bc28d8b0d61a779a55aba84f9c4" + integrity sha512-kqwoCMpGaj3zJedihUuVZWjISh+T72KAXOwgk6VKNf+APMTB8yLByLSgSLDhXsliRBO/9Pda/0g/KzGY7R+irQ== dependencies: "@babel/runtime" "^7.2.0" - "@material-ui/styles" "^4.1.2" + "@material-ui/styles" "^4.2.0" "@material-ui/system" "^4.3.0" "@material-ui/types" "^4.1.1" "@material-ui/utils" "^4.1.0" "@types/react-transition-group" "^2.0.16" clsx "^1.0.2" convert-css-length "^2.0.0" - debounce "^1.1.0" deepmerge "^3.0.0" hoist-non-react-statics "^3.2.1" is-plain-object "^3.0.0" normalize-scroll-left "^0.2.0" popper.js "^1.14.1" prop-types "^15.7.2" - react-event-listener "^0.6.6" react-transition-group "^4.0.0" warning "^4.0.1" -"@material-ui/styles@^4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.1.2.tgz#f22cb0d8f60a5e4a4b92f1ffb4b56f825ff89034" - integrity sha512-IRwhGI3OzxMKIDXnYl/vi9FD/i5ZktVP2m/5PIf/HVdvhqUZGIzqR2OB/9f3W1hc+kKKExdOPlpZpVihIsJWkA== +"@material-ui/styles@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.2.0.tgz#dafb8a271cb6772354aece15d3e43af33844f692" + integrity sha512-VpPCNWYK1KjpurFh1gH02xpAmCqKZrC/rmiBosZcCRDl8AOcUkSxBMNU0rziHgSQ/jYTEh3MdKNs3Gq0vGCQ/w== dependencies: "@babel/runtime" "^7.2.0" "@emotion/hash" "^0.7.1" @@ -3450,13 +3448,6 @@ auto-bind@2.0.0: resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-2.0.0.tgz#9a55a461b521f58daf955169203bed1a07a970a9" integrity sha512-rvRBv0/O7iriUMqSzTDhAfyAD1vVnElAEruo5rMSFeYLA0iKDEzLPSJiwMnL86+IPpTlhfOIAzjoKZ9TaySYdA== -auto-parse@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/auto-parse/-/auto-parse-1.7.0.tgz#7dd7f9dd4bd921744594c95c52ec4bc213a7c3b9" - integrity sha512-PLNPNt2gNRqIom895AsEeUo1HcDjfhDvxHW2pr+pTkTrI9CauqCD5AvYSEJ6tieES0Rb/88HK9+0m83uJNS2zw== - dependencies: - typpy "2.3.11" - autolinker@~0.15.0: version "0.15.3" resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832" @@ -4649,19 +4640,18 @@ cheerio@0.22.0: lodash.reject "^4.4.0" lodash.some "^4.4.0" -chokidar@3.0.1, chokidar@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.1.tgz#98fe9aa476c55d9aea7841d6325ffdb30e95b40c" - integrity sha512-2ww34sJWehnbpV0Q4k4V5Hh7juo7po6z7LUWkcIQnSGN1lHOL8GGtLtfwabKvLFQw/hbSUQ0u6V7OgGYgBzlkQ== +chokidar@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.2.tgz#0d1cd6d04eb2df0327446188cd13736a3367d681" + integrity sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA== dependencies: anymatch "^3.0.1" - async-each "^1.0.3" braces "^3.0.2" glob-parent "^5.0.0" is-binary-path "^2.1.0" is-glob "^4.0.1" normalize-path "^3.0.0" - readdirp "^3.0.2" + readdirp "^3.1.1" optionalDependencies: fsevents "^2.0.6" @@ -4684,6 +4674,22 @@ chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.4: optionalDependencies: fsevents "^1.2.7" +chokidar@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.1.tgz#98fe9aa476c55d9aea7841d6325ffdb30e95b40c" + integrity sha512-2ww34sJWehnbpV0Q4k4V5Hh7juo7po6z7LUWkcIQnSGN1lHOL8GGtLtfwabKvLFQw/hbSUQ0u6V7OgGYgBzlkQ== + dependencies: + anymatch "^3.0.1" + async-each "^1.0.3" + braces "^3.0.2" + glob-parent "^5.0.0" + is-binary-path "^2.1.0" + is-glob "^4.0.1" + normalize-path "^3.0.0" + readdirp "^3.0.2" + optionalDependencies: + fsevents "^2.0.6" + chownr@^1.0.1, chownr@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" @@ -5791,11 +5797,6 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debounce@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131" - integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg== - debug@0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" @@ -6161,7 +6162,7 @@ dir-glob@2.0.0: arrify "^1.0.1" path-type "^3.0.0" -dkim-signer@^0.2.2: +dkim-signer@0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/dkim-signer/-/dkim-signer-0.2.2.tgz#aa81ec071eeed3622781baa922044d7800e5f308" integrity sha1-qoHsBx7u02IngbqpIgRNeADl8wg= @@ -7560,13 +7561,6 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.name@^1.0.3: - version "1.0.12" - resolved "https://registry.yarnpkg.com/function.name/-/function.name-1.0.12.tgz#34eec84476d9fb67977924a4cdcb98ec85695726" - integrity sha512-C7Tu+rAFrWW5RjXqtKtXp2xOdCujq+4i8ZH3w0uz/xrYHBwXZrPt96x8cDAEHrIjeyEv/Jm6iDGyqupbaVQTlw== - dependencies: - noop6 "^1.0.1" - functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" @@ -8111,6 +8105,13 @@ graphql-upload@^8.0.2: http-errors "^1.7.2" object-path "^0.11.4" +graphql@14.4.1: + version "14.4.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.4.1.tgz#7a7818d3f63f66b9528ba5416b6c88460db62280" + integrity sha512-g4HUH26CohlMjaHneXMAtvG3QtO6peJIUTFxrPW4g5LNnXkUuFoBI6Bk1c14Q5kW8+FyjM/tTbePTgpiVB/2hQ== + dependencies: + iterall "^1.2.2" + graphql@14.4.2: version "14.4.2" resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.4.2.tgz#553a7d546d524663eda49ed6df77577be3203ae3" @@ -10373,10 +10374,10 @@ libqp@1.1.0: resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" integrity sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g= -lint-staged@9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-9.0.2.tgz#238e1ed7cba2d422faaf4499e6a5686f0f5c1331" - integrity sha512-2W9yBRADEzcGs6j/57JA0GVzSTByYgWbcU89/Xm0s/k+4qMp8032tZYPPmP422xZ79xtUaNisJ/0U5lbuYmaTA== +lint-staged@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-9.1.0.tgz#24564128c9208bf5d8001a66afe7156dfbe9da30" + integrity sha512-jI+oj159MHVlsGxMFkzTPrin0Jt8ltVJWSfCPn/xM+qiIPwCimjuhq9//IiNMaNj8VIFZ8QlaAF4qecWTbUOPQ== dependencies: chalk "^2.4.2" commander "^2.20.0" @@ -10823,7 +10824,7 @@ magic-string@^0.25.2: dependencies: sourcemap-codec "^1.4.4" -mailcomposer@^3.12.0: +mailcomposer@3.12.0: version "3.12.0" resolved "https://registry.yarnpkg.com/mailcomposer/-/mailcomposer-3.12.0.tgz#9c5e1188aa8e1c62ec8b86bd43468102b639e8f9" integrity sha1-nF4RiKqOHGLsi4a9Q0aBArY56Pk= @@ -11436,10 +11437,10 @@ neo-async@^2.5.0, neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== -netlify-lambda@1.4.13: - version "1.4.13" - resolved "https://registry.yarnpkg.com/netlify-lambda/-/netlify-lambda-1.4.13.tgz#a324615133b8f1a3aaeec8c5dfc825cf07aaddf1" - integrity sha512-f8CeAt8iGeORFn6fcNn3UXNSjGPL8vWaLm3yZH6I7txENOOdKMp7SdwvNL5YEN3s5h9+GAQ05qy3Ems0nle2JQ== +netlify-lambda@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/netlify-lambda/-/netlify-lambda-1.5.0.tgz#52b1a16af73b3eeb1dee3c6178f189f010dd6450" + integrity sha512-Np1+dGu850o5qVzVlUlvuLD7M2QzL9HuH0BqKZisXtFPz8SYLv7Ulyj1GNYnUfBBa6SnZAQ+wU4L4u3laGm7Ww== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" @@ -11606,11 +11607,6 @@ noop-logger@^0.1.1: resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= -noop6@^1.0.1: - version "1.0.8" - resolved "https://registry.yarnpkg.com/noop6/-/noop6-1.0.8.tgz#eff06e2e5b3621e9e5618f389d6a2294f76e64ad" - integrity sha512-+Al5csMVc40I8xRfJsyBcN1IbpyvebOuQmMfxdw+AL6ECELey12ANgNTRhMfTwNIDU4W9W0g8EHLcsb3+3qPFA== - "nopt@2 || 3": version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -13655,7 +13651,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -14018,15 +14014,6 @@ react-error-overlay@^5.1.6: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.6.tgz#0cd73407c5d141f9638ae1e0c63e7b2bf7e9929d" integrity sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q== -react-event-listener@^0.6.6: - version "0.6.6" - resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.6.tgz#758f7b991cad9086dd39fd29fad72127e1d8962a" - integrity sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw== - dependencies: - "@babel/runtime" "^7.2.0" - prop-types "^15.6.0" - warning "^4.0.1" - react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4: version "16.8.6" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" @@ -14266,6 +14253,13 @@ readdirp@^3.0.2: dependencies: picomatch "^2.0.4" +readdirp@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.1.tgz#b158123ac343c8b0f31d65680269cc0fc1025db1" + integrity sha512-XXdSXZrQuvqoETj50+JAitxz1UPdt5dupjT6T5nVB+WvjMv2XKYj+s7hPeAVCXvmJrL36O4YYyWlIC3an2ePiQ== + dependencies: + picomatch "^2.0.4" + realpath-native@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" @@ -15078,14 +15072,13 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -sendmail@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/sendmail/-/sendmail-1.6.0.tgz#8cc192cb8e2e88b393cd41c4c1207d50b131d29c" - integrity sha512-2lnZZNvejv+F0UdNsOF9fE4DWUx16ijd+47D5tl3dOSp+hpAHipr56UUBzYfx+r38GRarhWNZRpFhPAf3pZ7Kg== +sendmail@1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/sendmail/-/sendmail-1.6.1.tgz#6be92fb4be70d1d9ad102030aeb1e737bd512159" + integrity sha512-lIhvnjSi5e5jL8wA1GPP6j2QVlx6JOEfmdn0QIfmuJdmXYGmJ375kcOU0NSm/34J+nypm4sa1AXrYE5w3uNIIA== dependencies: - auto-parse "^1.7.0" - dkim-signer "^0.2.2" - mailcomposer "^3.12.0" + dkim-signer "0.2.2" + mailcomposer "3.12.0" sentence-case@^2.1.0: version "2.1.1" @@ -16476,13 +16469,6 @@ typescript@>=2.8.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202" integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw== -typpy@2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/typpy/-/typpy-2.3.11.tgz#21a0d22c96fb646306e08b6c669ad43608e1b3b9" - integrity sha512-Jh/fykZSaxeKO0ceMAs6agki9T5TNA9kiIR6fzKbvafKpIw8UlNlHhzuqKyi5lfJJ5VojJOx9tooIbyy7vHV/g== - dependencies: - function.name "^1.0.3" - uglify-js@3.4.x: version "3.4.10" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"