or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

@graphql-codegen/typescript-document-nodes

A GraphQL Code Generator plugin that generates TypeScript modules with embedded GraphQL document nodes, enabling strongly-typed GraphQL operations with compile-time safety and automatic fragment resolution.

Package Information

  • Package Name: @graphql-codegen/typescript-document-nodes
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @graphql-codegen/typescript-document-nodes

Core Imports

// ES6 modules
import { 
  plugin, 
  validate,
  TypeScriptDocumentNodesVisitor
} from "@graphql-codegen/typescript-document-nodes";
import type { 
  TypeScriptDocumentNodesRawPluginConfig,
  TypeScriptDocumentNodesPluginConfig
} from "@graphql-codegen/typescript-document-nodes";
import type { Types } from "@graphql-codegen/plugin-helpers";
import type { GraphQLSchema } from "graphql";

// CommonJS
const { 
  plugin, 
  validate, 
  TypeScriptDocumentNodesVisitor 
} = require("@graphql-codegen/typescript-document-nodes");
const { Types } = require("@graphql-codegen/plugin-helpers");

Basic Usage

This plugin is designed to be used with GraphQL Code Generator to transform GraphQL documents into TypeScript modules with embedded document nodes:

// codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'schema.graphql',
  documents: 'src/**/*.graphql',
  generates: {
    'src/generated/document-nodes.ts': {
      plugins: ['typescript-document-nodes']
    }
  }
};
export default config;

Given a GraphQL query file:

# queries/user.graphql
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
    email
  }
}

The plugin generates:

export const GetUser = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

Architecture

Key Components

  • Plugin Function: Main entry point that processes GraphQL documents and generates TypeScript code
  • Visitor Class: Handles document traversal and code generation logic
  • Configuration Interface: Defines customization options for naming and output formatting
  • Validation Function: Ensures output files have correct .ts extension

Processing Flow

  1. Document Collection: Aggregates all GraphQL documents and fragments
  2. Fragment Analysis: Identifies and processes fragment dependencies
  3. Code Generation: Creates TypeScript constants with gql template literals
  4. Output Assembly: Combines generated code with necessary imports

Capabilities

Plugin Function

/**
 * Main plugin function that processes GraphQL documents and generates TypeScript modules
 * @param schema - GraphQL schema object (can be null)
 * @param documents - Array of GraphQL document files
 * @param config - Plugin configuration options
 * @returns Generated TypeScript code with imports and content
 */
function plugin(
  schema: GraphQLSchema | null,
  documents: Types.DocumentFile[],
  config: TypeScriptDocumentNodesRawPluginConfig
): Types.ComplexPluginOutput;

Configuration Interfaces

/**
 * Configuration options for the TypeScript Document Nodes plugin (user input)
 */
interface TypeScriptDocumentNodesRawPluginConfig extends RawClientSideBasePluginConfig {
  /**
   * Naming convention for generated variable names
   * @default "change-case-all#pascalCase"
   */
  namingConvention?: NamingConvention;
  
  /**
   * Prefix added to generated variable names
   * @default ""
   */
  namePrefix?: string;
  
  /**
   * Suffix added to generated variable names
   * @default ""
   */
  nameSuffix?: string;
  
  /**
   * Prefix added to fragment variable names
   * @default ""
   */
  fragmentPrefix?: string;
  
  /**
   * Suffix added to fragment variable names
   * @default ""
   */
  fragmentSuffix?: string;
  
  /**
   * External fragments to include in the visitor
   * @default []
   */
  externalFragments?: LoadedFragment[];
}

/**
 * Processed configuration interface used internally by the visitor
 */
interface TypeScriptDocumentNodesPluginConfig extends ClientSideBasePluginConfig {
  /**
   * Naming convention for generated variable names
   */
  namingConvention: NamingConvention;
  
  /**
   * Whether to transform underscores in names
   */
  transformUnderscore: boolean;
}

Additional Type Definitions

/**
 * Fragment definition loaded into the visitor
 */
interface LoadedFragment {
  /** Fragment name */
  name: string;
  /** Type this fragment is defined on */
  onType: string;
  /** GraphQL fragment definition node */
  node: FragmentDefinitionNode;
  /** Whether this fragment is external to current document set */
  isExternal: boolean;
  /** Import source if external fragment */
  importFrom?: string | null;
}

/**
 * Document file containing GraphQL operations
 */
interface DocumentFile {
  /** File location path */
  location: string;
  /** Parsed GraphQL document node */
  document: DocumentNode;
}

/**
 * Plugin output with prepend imports and content
 */
interface ComplexPluginOutput {
  /** Import statements to prepend */
  prepend: string[];
  /** Generated content */
  content: string;
}

Validation Function

/**
 * Validates plugin configuration and output file requirements
 * @param schema - GraphQL schema object (can be null)
 * @param documents - Array of GraphQL document files
 * @param config - Plugin configuration
 * @param outputFile - Output file path
 * @throws Error if output file doesn't end with .ts
 */
function validate(
  schema: GraphQLSchema | null,
  documents: Types.DocumentFile[],
  config: any,
  outputFile: string
): Promise<void>;

Visitor Class

/**
 * Visitor class that handles document traversal and code generation
 * This class is exported and available for extension or custom implementations
 */
class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
  TypeScriptDocumentNodesRawPluginConfig,
  TypeScriptDocumentNodesPluginConfig
> {
  /**
   * Creates a new visitor instance
   * @param schema - GraphQL schema
   * @param fragments - Array of loaded fragments
   * @param rawConfig - Raw plugin configuration
   * @param documents - Array of document files
   */
  constructor(
    schema: GraphQLSchema,
    fragments: LoadedFragment[],
    rawConfig: TypeScriptDocumentNodesRawPluginConfig,
    documents: Types.DocumentFile[]
  );
  
  /**
   * Returns import statements to be prepended to generated output
   * Inherited from ClientSideBaseVisitor
   */
  getImports(): string[];
  
  /**
   * Fragment definitions as string
   * Inherited from ClientSideBaseVisitor
   */
  fragments: string;
}

Usage Examples

Basic Document Generation

// Configuration
const config: TypeScriptDocumentNodesRawPluginConfig = {};

// Usage with GraphQL Code Generator
const result = plugin(schema, documents, config);
// Generates: export const MyQuery = gql`query MyQuery { ... }`;

Custom Naming Convention

// Using camelCase naming
const config: TypeScriptDocumentNodesRawPluginConfig = {
  namingConvention: 'change-case-all#camelCase'
};

// Generated output changes from MyQuery to myQuery

Prefixes and Suffixes

// Adding prefixes and suffixes
const config: TypeScriptDocumentNodesRawPluginConfig = {
  namePrefix: 'Gql',
  nameSuffix: 'Document',
  fragmentPrefix: 'Fragment',
  fragmentSuffix: 'Part'
};

// Transforms MyQuery to GqlMyQueryDocument
// Transforms UserFragment to FragmentUserFragmentPart

Fragment Handling

// Input GraphQL with fragments
const fragmentQuery = `
  fragment UserInfo on User {
    id
    name
    email
  }
  
  query GetUserWithProfile($id: ID!) {
    user(id: $id) {
      ...UserInfo
      profile {
        bio
      }
    }
  }
`;

// Generated output includes fragment composition
// export const UserInfo = gql`fragment UserInfo on User { ... }`;
// export const GetUserWithProfile = gql`query GetUserWithProfile($id: ID!) { ... }\${UserInfo}`;

Advanced Configuration

// Complex naming and transformation options
const config: TypeScriptDocumentNodesRawPluginConfig = {
  namingConvention: {
    typeNames: 'change-case-all#pascalCase',
    transformUnderscore: true
  },
  namePrefix: 'Generated',
  nameSuffix: 'Query'
};

// Transforms query names with underscores and applies prefix/suffix

External Fragments

// Including external fragments from other files
const config: TypeScriptDocumentNodesRawPluginConfig = {
  externalFragments: [
    {
      name: 'UserFields',
      onType: 'User',
      node: userFieldsFragmentNode,
      isExternal: true,
      importFrom: './user-fragments'
    }
  ]
};

// External fragments will be available for composition in generated queries

Multiple Document Processing

// Processing multiple GraphQL files
const documents = [
  { location: 'queries/user.graphql', document: userQueryAst },
  { location: 'queries/posts.graphql', document: postsQueryAst },
  { location: 'fragments/common.graphql', document: fragmentsAst }
];

const result = plugin(schema, documents, config);
// Generates TypeScript constants for all named operations

Integration with GraphQL Clients

// Generated code can be used directly with GraphQL clients
import { GetUser } from './generated/document-nodes';
import { useQuery } from '@apollo/client';

// Apollo Client usage
const { data, loading, error } = useQuery(GetUser, {
  variables: { id: '123' }
});

// Other GraphQL clients
const result = await graphqlClient.request(GetUser, { id: '123' });

Advanced: Extending the Visitor Class

For advanced customization, you can extend the visitor class to modify code generation behavior:

import { 
  TypeScriptDocumentNodesVisitor,
  TypeScriptDocumentNodesRawPluginConfig 
} from "@graphql-codegen/typescript-document-nodes";
import { GraphQLSchema } from "graphql";

class CustomDocumentNodesVisitor extends TypeScriptDocumentNodesVisitor {
  constructor(
    schema: GraphQLSchema,
    fragments: LoadedFragment[],
    rawConfig: TypeScriptDocumentNodesRawPluginConfig,
    documents: Types.DocumentFile[]
  ) {
    super(schema, fragments, rawConfig, documents);
  }

  // Override methods to customize generation behavior
  // Access to all parent class methods and properties
}

// Use custom visitor in your own plugin implementation
const customResult = oldVisit(ast, { leave: new CustomDocumentNodesVisitor(...) });

Validation Requirements

The plugin enforces these validation rules:

  • File Extension: Output files must have .ts extension
  • Named Operations: Only named GraphQL operations are processed (unnamed operations are ignored)
  • Fragment Resolution: All fragment dependencies must be resolvable
  • TypeScript Compatibility: Generated code must be valid TypeScript

Error Handling

// Validation errors
try {
  await validate(schema, documents, config, 'output.js');
} catch (error) {
  // Error: Plugin "typescript-document-nodes" requires extension to be ".ts"!
}

// Configuration errors are handled during plugin execution
// Fragment resolution errors are handled during document processing

Integration Patterns

With Other GraphQL Code Generator Plugins

// Combining with other plugins for complete type safety
const config: CodegenConfig = {
  generates: {
    'src/generated/types.ts': {
      plugins: ['typescript']
    },
    'src/generated/document-nodes.ts': {
      plugins: ['typescript-document-nodes'],
      config: {
        namingConvention: 'change-case-all#pascalCase'
      }
    }
  }
};

With Build Systems

// Integration with build tools
import { plugin } from '@graphql-codegen/typescript-document-nodes';

// Custom build script
const generateDocuments = async () => {
  const result = plugin(schema, documents, config);
  await writeFile('output.ts', result.prepend.join('\n') + '\n' + result.content);
};