Repository: graphql-markdown/graphql-markdown
Pull request #1299 (2024-02-16 22:22:54)

:sparkle: (wip) support examples - format & customisation
# Description

Add example formatting and support for customization.

```ts
interface TypeExampleSectionOption {
  directive?: string; // customize the directive name
  field?: string; // customize the directive's field name
  parser?: (value?: unknown) => unknown; // customize the field's value parsing
}
```

# Checklist

- [x] My changes follow the [contributing guidelines](https://github.com/graphql-markdown/graphql-markdown/blob/main/CONTRIBUTING.md) of this project.
- [x] I have performed a self-review of my code.
- [x] I have made corresponding changes to the documentation.
- [x] I have added tests that prove my fix is effective or that my changes work.
- [x] New and existing unit tests pass locally with my changes.


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=graphql-markdown_graphql-markdown&pullRequest=1299) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [1 New Critical Issues](https://sonarcloud.io/dashboard?id=graphql-markdown_graphql-markdown&pullRequest=1299) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=graphql-markdown_graphql-markdown&pullRequest=1299)

##   
![idea](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png 'idea') Catch issues before they fail your Quality Gate with our IDE extension ![SonarLint](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png 'SonarLint') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


coveralls: 
[![Coverage Status](https://coveralls.io/builds/65754852/badge)](https://coveralls.io/builds/65754852)

coverage: 94.249% (-0.07%) from 94.319%
when pulling **19db1a730fae2fb749a6aca4d214973d538c64f1 on feat/1292-support-examples-2**
into **79e34d54b959d01cc06352f88b37f507bc4b780e on main**.

sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=graphql-markdown_graphql-markdown&pullRequest=1299) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=graphql-markdown_graphql-markdown&pullRequest=1299&resolved=false&inNewCodePeriod=true)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=graphql-markdown_graphql-markdown&pullRequest=1299&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1.1% Duplication on New Code](https://sonarcloud.io/component_measures?id=graphql-markdown_graphql-markdown&pullRequest=1299&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=graphql-markdown_graphql-markdown&pullRequest=1299)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=graphql-markdown_graphql-markdown&pullRequest=1299) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=graphql-markdown_graphql-markdown&pullRequest=1299&resolved=false&inNewCodePeriod=true)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=graphql-markdown_graphql-markdown&pullRequest=1299&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1.1% Duplication on New Code](https://sonarcloud.io/component_measures?id=graphql-markdown_graphql-markdown&pullRequest=1299&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=graphql-markdown_graphql-markdown&pullRequest=1299)



Patch:
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 536a6a24..35349148 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -62,6 +62,7 @@
     "Repulsorcraft",
     "Snyk",
     "socio",
+    "spectaql",
     "Starfighter",
     "Starships",
     "swapi",
diff --git a/docs/advanced/examples.md b/docs/advanced/examples.md
index e85d9e59..162f88e9 100644
--- a/docs/advanced/examples.md
+++ b/docs/advanced/examples.md
@@ -4,3 +4,98 @@ pagination_next: null
 ---
 
 # Examples
+
+Using the option [`printTypeOptions.exampleSection`](/docs/settings#printtypeoptions), you can add examples to types documentation.
+
+## Usage
+
+**1. Add a type definition directive `@example` to the schema**
+
+  ```graphql
+  directive @example(
+    value: String
+  ) on OBJECT | INPUT_OBJECT | INTERFACE | FIELD_DEFINITION | ARGUMENT_DEFINITION | SCALAR
+  ```
+
+**2. Enrich your types definitions with examples**
+
+  ```graphql
+  scalar Date @example(value: "1970-01-01")
+
+  interface Record {
+    id: ID! @example(value: "1")
+  }
+
+  type Course implements Record @example(value: "{ \"id\": 2, \"title\": \"GraphQL\" }") {
+    id: ID!
+    title: String!
+  } 
+
+  type Semester implements Record {
+    id: ID!
+    startDate: Date
+    withdrawDate: Date @deprecated
+    endDate: Date
+    courses: [Course!]!
+  }
+  ```
+
+Examples can be inherited, this is why in the above example there is no example explicitly set for the type `Semester`, and it will render as following
+
+![examples](/img/docs/examples.png)
+
+## Custom directive example
+
+Example directive definition and parser behavior can be customized through the configuration using a `TypeDirectiveExample` object instead of a boolean value for `printTypeOptions.exampleSection`:
+
+```ts
+interface TypeExampleSectionOption {
+  directive?: string; // customize the directive name
+  field?: string; // customize the directive's field name
+  parser?: (value?: unknown) => unknown; // customize the field's value parsing
+}
+```
+
+For example, if the GraphQL schema already supports examples using the `@spectaql` directive.
+
+```graphql
+type CustomExampleDirective {
+  myField: String @spectaql(options: [{ key: "undocumented", value: "true" }])
+  myFieldOtherField: String @spectaql(options: [{ key: "example", value: "An Example from the Directive" }])
+  myFieldOtherOtherField: String @spectaql(options: [{ key: "examples", value: "[\"Example 1 from the Directive\", \"Example 2 from the Directive\"]" }])
+}
+```
+
+```js title="docusaurus.config.js"
+plugins: [
+  [
+    "@graphql-markdown/docusaurus",
+    {
+      // ... other options
+      printTypeOptions: {
+        exampleSection: {
+          directive: schema.getDirective("spectaql")!,
+          field: "options",
+          parser: (options: unknown): string | undefined => {
+            const example = (options as [{ key: string; value: string }]).find(
+              (option) => {
+                return ["example", "examples"].includes(option.key);
+              },
+            );
+
+            if (!example) {
+              return undefined;
+            }
+
+            if (example.key === "example") {
+              return example.value;
+            }
+
+            return (JSON.parse(example.value) as string[])[0];
+          }
+        }
+      }
+    }
+  ]
+]
+```
diff --git a/packages/graphql/src/guard.ts b/packages/graphql/src/guard.ts
index 93a885c9..f45f24f8 100644
--- a/packages/graphql/src/guard.ts
+++ b/packages/graphql/src/guard.ts
@@ -24,6 +24,7 @@ export {
   isNonNullType,
   isObjectType,
   isScalarType,
+  isType,
   isUnionType,
 } from "graphql";
 
diff --git a/packages/graphql/src/introspection.ts b/packages/graphql/src/introspection.ts
index 60dcccf9..4e378df3 100644
--- a/packages/graphql/src/introspection.ts
+++ b/packages/graphql/src/introspection.ts
@@ -38,7 +38,7 @@ import { convertArrayToMapObject } from "@graphql-markdown/utils";
 
 import { instanceOf } from "./guard";
 
-export { getNamedType, printSchema } from "graphql";
+export { getNamedType, printSchema, getNullableType } from "graphql";
 
 export class IntrospectionError extends Error {}
 
@@ -320,7 +320,11 @@ export const _getFields = <T, V>(
    */
   processor?: (fieldMap: Record<string, unknown>) => V,
   fallback?: V,
-): GraphQLFieldMap<unknown, unknown> | GraphQLInputFieldMap | V => {
+):
+  | GraphQLFieldMap<unknown, unknown>
+  | GraphQLInputFieldMap
+  | GraphQLObjectType
+  | V => {
   if (
     !(
       typeof type === "object" &&
diff --git a/packages/printer-legacy/src/example.ts b/packages/printer-legacy/src/example.ts
index 64099a75..8ae4a4c5 100644
--- a/packages/printer-legacy/src/example.ts
+++ b/packages/printer-legacy/src/example.ts
@@ -1,50 +1,106 @@
-import type { Maybe, GraphQLDirective } from "@graphql-markdown/types";
+import type {
+  GraphQLType,
+  Maybe,
+  TypeDirectiveExample,
+} from "@graphql-markdown/types";
 
 import {
-  IntrospectionError,
   getFields,
+  getNamedType,
+  getNullableType,
   getTypeDirectiveArgValue,
   hasDirective,
+  IntrospectionError,
+  isListType,
+  isType,
 } from "@graphql-markdown/graphql";
 
-export const printExample = (
-  type: unknown,
-  directiveExample: {
-    directive: GraphQLDirective;
-    argName: string;
-  },
-): Maybe<string> => {
+const parseTypeFields = (
+  type: Maybe<GraphQLType>,
+  directiveExample: TypeDirectiveExample,
+): Maybe<unknown> => {
+  const fields = getFields(type) as {
+    astNode: unknown;
+    name: string;
+    type: unknown;
+  }[];
+
+  if (fields.length === 0) {
+    return undefined;
+  }
+
+  let example: Record<string, unknown> = {};
+  fields.forEach((field) => {
+    const fieldType = hasDirective(field, [directiveExample.directive])
+      ? field
+      : field.type;
+    // eslint-disable-next-line @typescript-eslint/no-use-before-define
+    const value = parseExampleDirective(
+      fieldType as Maybe<GraphQLType>,
+      directiveExample,
+    );
+    example = {
+      ...example,
+      [field.name]: isListType(getNullableType(fieldType as Maybe<GraphQLType>))
+        ? [value]
+        : value,
+    };
+  });
+
+  return example;
+};
+
+const parseExampleValue = (value: unknown): Maybe<unknown> => {
+  if (!value || typeof value !== "string") {
+    return undefined;
+  }
+
+  try {
+    return JSON.parse(value);
+  } catch (err: unknown) {
+    return value;
+  }
+};
+
+const parseExampleDirective = (
+  type: Maybe<GraphQLType>,
+  directiveExample: TypeDirectiveExample,
+): Maybe<unknown> => {
+  const parser =
+    typeof directiveExample.parser === "function"
+      ? directiveExample.parser
+      : parseExampleValue;
+
+  const namedType = getNamedType(type);
+  if (!namedType) {
+    return undefined;
+  }
+
   try {
     const arg = getTypeDirectiveArgValue(
       directiveExample.directive,
-      type,
-      directiveExample.argName,
-    );
+      namedType,
+      directiveExample.field,
+    ) as unknown;
 
-    return arg ? String(arg) : undefined;
+    return parser(arg);
   } catch (err: unknown) {
     if (err instanceof IntrospectionError) {
-      const fields = getFields(type) as {
-        astNode: unknown;
-        name: string;
-        type: unknown;
-      }[];
-      if (fields.length === 0) {
-        return undefined;
-      }
-
-      let example = {};
-      fields.forEach((field) => {
-        const fieldType = hasDirective(field, [directiveExample.directive])
-          ? field
-          : field.type;
-        example = {
-          ...example,
-          [field.name]: printExample(fieldType, directiveExample),
-        };
-      });
-      return JSON.stringify(example);
+      return parseTypeFields(namedType, directiveExample);
     }
     throw err;
   }
 };
+
+export const printExample = (
+  type: unknown,
+  directiveExample: TypeDirectiveExample,
+): Maybe<string> => {
+  if (!isType(type)) {
+    return undefined;
+  }
+
+  const example = parseExampleDirective(type, directiveExample);
+
+  return JSON.stringify(example, undefined, 2);
+};
diff --git a/packages/printer-legacy/src/printer.ts b/packages/printer-legacy/src/printer.ts
index 52580219..f8a08ff3 100644
--- a/packages/printer-legacy/src/printer.ts
+++ b/packages/printer-legacy/src/printer.ts
@@ -215,8 +215,8 @@ export class Printer implements IPrinter {
       ) {
         directiveName = options.exampleSection.directive;
       }
-      if ("arg" in options.exampleSection && options.exampleSection.arg) {
-        argName = options.exampleSection.arg;
+      if ("field" in options.exampleSection && options.exampleSection.field) {
+        argName = options.exampleSection.field;
       }
     }
 
@@ -226,7 +226,7 @@ export class Printer implements IPrinter {
       return "";
     }
 
-    const example = printExample(type, { directive, argName });
+    const example = printExample(type, { directive, field: argName });
 
     if (!example) {
       return "";
diff --git a/packages/types/src/core.d.ts b/packages/types/src/core.d.ts
index 1ed68f7c..fba6728a 100644
--- a/packages/types/src/core.d.ts
+++ b/packages/types/src/core.d.ts
@@ -1,7 +1,12 @@
 import type { UnnormalizedTypeDefPointer } from "@graphql-tools/load";
 import type { BaseLoaderOptions } from "@graphql-tools/utils";
 
-import type { CustomDirective, DirectiveName, GraphQLSchema } from ".";
+import type {
+  CustomDirective,
+  DirectiveName,
+  GraphQLDirective,
+  GraphQLSchema,
+} from ".";
 
 export type FrontMatterOptions = Record<string, unknown>;
 
@@ -22,10 +27,22 @@ export interface DeprecatedConfigDocOptions {
 
 export type TypeDeprecatedOption = "default" | "group" | "skip";
 
+export type DirectiveExampleParserFunction = (value?: unknown) => unknown;
+
+export interface TypeDirectiveExample {
+  directive: GraphQLDirective;
+  field: string;
+  parser?: DirectiveExampleParserFunction;
+}
+
+export type TypeExampleSectionOption = Partial<
+  Omit<TypeDirectiveExample, "directive"> & { directive: string }
+>;
+
 export interface ConfigPrintTypeOptions {
   codeSection?: boolean;
   deprecated?: TypeDeprecatedOption;
-  exampleSection?: boolean;
+  exampleSection?: TypeExampleSectionOption | boolean;
   parentTypePrefix?: boolean;
   relatedTypeSection?: boolean;
   typeBadges?: boolean;
diff --git a/packages/types/src/printer.d.ts b/packages/types/src/printer.d.ts
index baf148ce..4846b403 100644
--- a/packages/types/src/printer.d.ts
+++ b/packages/types/src/printer.d.ts
@@ -7,6 +7,7 @@ import type {
   ConfigPrintTypeOptions,
   GraphQLDirective,
   FrontMatterOptions,
+  TypeExampleSectionOption,
 } from ".";
 
 export type RootTypeName =
@@ -28,7 +29,7 @@ export type RootTypeLocale = {
 
 export interface PrinterConfigPrintTypeOptions {
   codeSection?: boolean;
-  exampleSection?: ExampleDirectiveOption | boolean;
+  exampleSection?: TypeExampleSectionOption | boolean;
   deprecated?: TypeDeprecatedOption;
   metatags?: Record<string, string>[];
   parentTypePrefix?: boolean;
@@ -42,18 +43,13 @@ export interface CollapsibleOption {
   dataClose: string;
 }
 
-export interface ExampleDirectiveOption {
-  directive?: string;
-  arg?: string;
-}
-
 export interface PrintTypeOptions {
   basePath: string;
   codeSection?: Maybe<boolean>;
   collapsible?: Maybe<CollapsibleOption>;
   customDirectives?: Maybe<CustomDirectiveMap>;
   deprecated?: Maybe<TypeDeprecatedOption>;
-  exampleSection?: Maybe<ExampleDirectiveOption | boolean>;
+  exampleSection?: Maybe<TypeExampleSectionOption | boolean>;
   frontMatter?: Maybe<FrontMatterOptions>;
   groups?: Maybe<SchemaEntitiesGroupMap>;
   level?: Maybe<SectionLevelValue>;


Test patch:
diff --git a/packages/docusaurus/tests/__data__/schema_with_grouping.graphql b/packages/docusaurus/tests/__data__/schema_with_grouping.graphql
index 3b1b6ca8..d9ca0ccd 100644
--- a/packages/docusaurus/tests/__data__/schema_with_grouping.graphql
+++ b/packages/docusaurus/tests/__data__/schema_with_grouping.graphql
@@ -5,7 +5,7 @@ See [documentation](https://graphql-markdown.github.io/docs/settings#printtypeop
 """
 directive @example(
   value: String
-) on OBJECT | INPUT_OBJECT | UNION | ENUM | INTERFACE | FIELD_DEFINITION | ARGUMENT_DEFINITION | QUERY | MUTATION | SCALAR
+) on OBJECT | INPUT_OBJECT | INTERFACE | FIELD_DEFINITION | ARGUMENT_DEFINITION | SCALAR
 
 """
 Example of custom directive for `skipDocDirective`.
@@ -45,7 +45,7 @@ directive @complexity(
 
   Use parameters values to compute the field's cost dynamically. If the parameter is an array, its multiplier value will be the length of the array.
   """
-  multipliers: [String!] @example(value: "[\\\"roles\\\"]")
+  multipliers: [String!] @example(value: "[\"roles\"]")
 ) on FIELD_DEFINITION
 
 """
@@ -82,11 +82,11 @@ type Mutation {
 }
 
 type Mutation {
-  AddCourse(input: String): String @doc(category: "Course") @auth
+  AddCourse(input: String): Course @doc(category: "Course") @auth
 }
 
 type Mutation {
-  DropCourse(input: String): String @doc(category: "Course") @auth
+  DropCourse(input: String): Course @doc(category: "Course") @auth
 }
 
 enum Roles {
@@ -102,13 +102,13 @@ type Query {
   UnWeightedGPA(input: String, skip: Int!): Int
     @doc(category: "Grade")
     @complexity(value: 3)
-  Course(skip: Int = 0): Course @doc(category: "Course")
+  Course(skip: Int = 0): Course @doc(category: "Course") @example(value: "{\n Course(skip: 1)\n {\n id\n title\n }\n }")
 }
 
 type Query {
-  allCourses: [String] @doc(category: "Course")
-  mathCourses: [String] @doc(category: "Course") @deprecated
-  scienceCourses: [String] @doc(category: "Course") @deprecated
+  allCourses: [Course] @doc(category: "Course")
+  mathCourses: [Course] @doc(category: "Course") @deprecated
+  scienceCourses: [Course] @doc(category: "Course") @deprecated
   searchRole(roles: [Roles!]! = [ADMIN]): Int!
     @beta
     @auth
@@ -142,10 +142,10 @@ type DepartmentInformation implements Record @auth {
   departmentOpenTime: Time
   departmentCloseTime: Time
   website: URL
-  employees(skip: Int): [String!]! @example(value: "[\\\"John Doe\\\"]")
+  employees(skip: Int): [String!]! @example(value: "[\"John Doe\"]")
 }
 
-type Course {
-  id: ID! @example(value: "1")
-  title: String! @example(value: "GraphQL")
+type Course implements Record @example(value: "{ \"id\": 2, \"title\": \"GraphQL\" }") {
+  id: ID!
+  title: String!
 }
diff --git a/packages/printer-legacy/tests/unit/example.test.ts b/packages/printer-legacy/tests/unit/example.test.ts
index e21c1111..54002f40 100644
--- a/packages/printer-legacy/tests/unit/example.test.ts
+++ b/packages/printer-legacy/tests/unit/example.test.ts
@@ -23,6 +23,29 @@ describe("example", () => {
     value: JSON
     id: ID!
   }
+
+  type TypeListExample {
+    example: [ScalarExample!]!
+  }
+
+  type TypeComplexExample {
+    example: [TypeListExample!]!
+  }
+
+  input SpectaQLInput {
+    key: String!
+    value: String!
+  }
+
+  directive @spectaql(
+    options: [SpectaQLInput!]!
+  ) on OBJECT | FIELD_DEFINITION | SCALAR
+
+  type CustomExampleDirective {
+    myField: String @spectaql(options: [{ key: "undocumented", value: "true" }])
+    myFieldOtherField: String @spectaql(options: [{ key: "example", value: "An Example from the Directive" }])
+    myFieldOtherOtherField: String @spectaql(options: [{ key: "examples", value: "[\\"Example 1 from the Directive\\", \\"Example 2 from the Directive\\"]" }])
+  }
 `);
   const exampleDirective = schema.getDirective("example")!;
 
@@ -33,9 +56,9 @@ describe("example", () => {
       expect(
         printExample(schema.getType("ScalarExample"), {
           directive: exampleDirective,
-          argName: "value",
+          field: "value",
         }),
-      ).toBe("This is an example");
+      ).toBe('"This is an example"');
     });
 
     test("returns undefined if no example directive", () => {
@@ -44,21 +67,35 @@ describe("example", () => {
       expect(
         printExample(schema.getType("JSON"), {
           directive: exampleDirective,
-          argName: "value",
+          field: "value",
         }),
       ).toBeUndefined();
     });
 
+    test("returns undefined if not a valid GraphQL type", () => {
+      expect.assertions(1);
+
+      expect(
+        printExample(
+          {},
+          {
+            directive: exampleDirective,
+            field: "value",
+          },
+        ),
+      ).toBeUndefined();
+    });
+
     test("returns JSON formatted string example using subtype examples", () => {
       expect.assertions(1);
 
       expect(
         printExample(schema.getType("TypeExtrapolateExample"), {
           directive: exampleDirective,
-          argName: "value",
+          field: "value",
         }),
       ).toBe(
-        '{"example":"This is an example","value":"{\\"example\\": \\"This is an example\\"}"}',
+        '{\n  "example": "This is an example",\n  "value": {\n    "example": "This is an example"\n  }\n}',
       );
     });
 
@@ -68,9 +105,60 @@ describe("example", () => {
       expect(
         printExample(schema.getType("TypeExample"), {
           directive: exampleDirective,
-          argName: "value",
+          field: "value",
+        }),
+      ).toBe('{\n  "example": "This is an example",\n  "value": {}\n}');
+    });
+
+    test("returns a formatted example supporting list format", () => {
+      expect.assertions(1);
+
+      expect(
+        printExample(schema.getType("TypeListExample"), {
+          directive: exampleDirective,
+          field: "value",
+        }),
+      ).toBe('{\n  "example": [\n    "This is an example"\n  ]\n}');
+    });
+
+    test("returns an extrapolated from complex types", () => {
+      expect.assertions(1);
+
+      expect(
+        printExample(schema.getType("TypeComplexExample"), {
+          directive: exampleDirective,
+          field: "value",
         }),
-      ).toBe('{"example": "This is an example", "value": {}}');
+      ).toBe(
+        '{\n  "example": [\n    {\n      "example": [\n        "This is an example"\n      ]\n    }\n  ]\n}',
+      );
+    });
+
+    test("returns a formatted example using custom parser", () => {
+      expect.assertions(1);
+
+      expect(
+        printExample(schema.getType("CustomExampleDirective"), {
+          directive: schema.getDirective("spectaql")!,
+          field: "options",
+          parser: (options: unknown): string | undefined => {
+            const example = (options as [{ key: string; value: string }]).find(
+              (option) => {
+                return ["example", "examples"].includes(option.key);
+              },
+            );
+            if (!example) {
+              return undefined;
+            }
+            if (example.key === "example") {
+              return example.value;
+            }
+            return (JSON.parse(example.value) as string[])[0];
+          },
+        }),
+      ).toBe(
+        '{\n  "myFieldOtherField": "An Example from the Directive",\n  "myFieldOtherOtherField": "Example 1 from the Directive"\n}',
+      );
     });
   });
 });
diff --git a/packages/printer-legacy/tests/unit/printer.test.ts b/packages/printer-legacy/tests/unit/printer.test.ts
index f48b8d8f..b1a36d84 100644
--- a/packages/printer-legacy/tests/unit/printer.test.ts
+++ b/packages/printer-legacy/tests/unit/printer.test.ts
@@ -489,7 +489,7 @@ describe("Printer", () => {
       });
 
       expect(spy).toHaveBeenCalledWith(GraphQLString, {
-        argName: "value",
+        field: "value",
         directive: { name: "example" },
       });
       expect(code).toMatchSnapshot();
@@ -532,7 +532,7 @@ describe("Printer", () => {
         ...DEFAULT_OPTIONS,
         exampleSection: {
           directive: "set",
-          arg: "examples",
+          field: "examples",
         },
         schema: {
           getDirective: (name: string) => {
@@ -542,7 +542,7 @@ describe("Printer", () => {
       });
 
       expect(spy).toHaveBeenCalledWith(GraphQLString, {
-        argName: "examples",
+        field: "examples",
         directive: { name: "set" },
       });
       expect(code).toMatchSnapshot();