CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-graphql-codegen--typescript-document-nodes

GraphQL Code Generator plugin for generating TypeScript modules with embedded GraphQL document nodes

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

@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);
};
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@graphql-codegen/typescript-document-nodes@4.0.x
Publish Source
CLI
Badge
tessl/npm-graphql-codegen--typescript-document-nodes badge