diff --git a/README.md b/README.md index c442ea7f..c4c23af2 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,12 @@ We use `@fake` directive to let you specify how to fake data. And if 60+ fakers pets: [Pet] @listLength(min: 1, max: 10) } +The `@override` directive can also be used to specify that an existing field should be overriden: + + extend type Post { + acticle: String! @override @fake(type: lorem, options: { loremSize: paragraphs }) + } + No need to remember or read any docs. Autocompletion is included! ## Features diff --git a/src/fake_definition.ts b/src/fake_definition.ts index 2b158207..e7950717 100644 --- a/src/fake_definition.ts +++ b/src/fake_definition.ts @@ -12,6 +12,7 @@ import { isObjectType, isInterfaceType, ValuesOfCorrectTypeRule, + DefinitionNode, } from 'graphql'; // FIXME @@ -220,6 +221,8 @@ const fakeDefinitionAST = parse(/* GraphQL */ ` scalar examples__JSON directive @examples(values: [examples__JSON]!) on FIELD_DEFINITION | SCALAR + + directive @override on FIELD_DEFINITION `); function defToName(defNode) { @@ -256,6 +259,14 @@ export function buildWithFakeDefinitions( }), }; + if (extensionSDL != null) { + // Remove fields marked with the @override annotation + filteredAST.definitions = filterFields( + filteredAST.definitions, + findFieldsWithOverrideDirective(extensionSDL), + ); + } + let schema = extendSchemaWithAST(schemaWithOnlyFakedDefinitions, filteredAST); const config = schema.toConfig(); @@ -311,6 +322,55 @@ export function buildWithFakeDefinitions( commentDescriptions: true, }); } + + function findFieldsWithOverrideDirective( + extensionSDL: Source, + ): Map { + const res = new Map(); + parseSDL(extensionSDL).definitions.map((d) => { + if (d.kind !== 'ObjectTypeExtension' || d.fields === undefined) { + return; + } + + const filteredFields = d.fields + .filter( + (f) => + f.directives?.findIndex((d) => d.name.value === 'override') !== -1, + ) + .map((f) => f.name.value); + + if (filteredFields.length > 0) { + res.set(d.name.value, filteredFields); + } + }); + + return res; + } + + function filterFields( + definitions: DefinitionNode[], + fieldsToRemove: Map, + ): DefinitionNode[] { + return definitions.map((d) => { + if ( + d.kind === 'ObjectTypeDefinition' && + d.fields !== undefined && + fieldsToRemove.has(d.name.value) + ) { + const toRemove = fieldsToRemove.get(d.name.value); + const filteredFields = d.fields.filter( + (f) => toRemove!.indexOf(f.name.value) === -1, + ); + + return { + ...d, + fields: filteredFields, + }; + } + + return d; + }); + } } // FIXME: move to 'graphql-js'