import { DetailedError , Types , CodegenPlugin , normalizeOutputParam , normalizeInstanceOrArray , normalizeConfig , getCachedDocumentNodeFromSchema , } from '@graphql-codegen/plugin-helpers' ; import { codegen } from '@graphql-codegen/core' ; import { Renderer , ErrorRenderer } from './utils/listr-renderer' ; import { GraphQLError , GraphQLSchema , DocumentNode } from 'graphql' ; import { getPluginByName } from './plugins' ; import { getPresetByName } from './presets' ; import { debugLog } from './utils/debugging' ; import { CodegenContext , ensureContext } from './config' ; import fs from 'fs' ; import path from 'path' ; import { createRequire } from 'module' ; import Listr from 'listr' ; const makeDefaultLoader = ( from ) => { if ( fs . statSync ( from ) . isDirectory ( ) ) { from = path . join ( from , '__fake.js' ) ; } const relativeRequire = createRequire ( from ) ; return ( mod ) => { return import ( relativeRequire . resolve ( mod ) ) ; } ; } ; export async function executeCodegen ( input ) { function wrapTask ( task , source ) { return async ( ) => { try { await Promise . resolve ( ) . then ( ( ) => task ( ) ) ; } catch ( error ) { if ( source && ! ( error instanceof GraphQLError ) ) { error . source = source ; } throw error ; } } ; } const context = ensureContext ( input ) ; const config = context . getConfig ( ) ; const pluginContext = context . getPluginContext ( ) ; const result = [ ] ; const commonListrOptions = { exitOnError : true , } ; let listr ; if ( process . env . VERBOSE ) { listr = new Listr ( { ... commonListrOptions , renderer : 'verbose' , nonTTYRenderer : 'verbose' , } ) ; } else if ( process . env . NODE_ENV === 'test' ) { listr = new Listr ( { ... commonListrOptions , renderer : 'silent' , nonTTYRenderer : 'silent' , } ) ; } else { listr = new Listr ( { ... commonListrOptions , renderer : config . silent ? 'silent' : config . errorsOnly ? ErrorRenderer : Renderer , nonTTYRenderer : config . silent ? 'silent' : 'default' , collapse : true , clearOutput : false , } as any ) ; } let rootConfig = { } ; let rootSchemas ; let rootDocuments ; const generates = { } ; async function normalize ( ) { const requireExtensions = normalizeInstanceOrArray < string > ( config . require ) ; const loader = makeDefaultLoader ( context . cwd ) ; for ( const mod of requireExtensions ) { await loader ( mod ) ; } rootConfig = config . config || { } ; rootSchemas = normalizeInstanceOrArray < Types . Schema > ( config . schema ) ; rootDocuments = normalizeInstanceOrArray < Types . OperationDocument > ( config . documents ) ; const generateKeys = Object . keys ( config . generates || { } ) ; if ( generateKeys . length === 0 ) { throw new DetailedError ( 'Invalid Codegen Configuration!' , `
        Please make sure that your codegen config file contains the "generates" field, with a specification for the plugins you need.

        It should looks like that:

        schema:
          - my-schema.graphql
        generates:
          my-file.ts:
            - plugin1
            - plugin2
            - plugin3
        ` ) ; } for ( const filename of generateKeys ) { const output = ( generates [ filename ] = normalizeOutputParam ( config . generates [ filename ] ) ) ; if ( ! output . preset && ( ! output . plugins || output . plugins . length === 0 ) ) { throw new DetailedError ( 'Invalid Codegen Configuration!' , `
          Please make sure that your codegen config file has defined plugins list for output "${ filename }".

          It should looks like that:

          schema:
            - my-schema.graphql
          generates:
            my-file.ts:
              - plugin1
              - plugin2
              - plugin3
          ` ) ; } } if ( rootSchemas . length === 0 && Object . keys ( generates ) . some ( filename => ! generates [ filename ] . schema || generates [ filename ] . schema . length === 0 ) ) { throw new DetailedError ( 'Invalid Codegen Configuration!' , `
        Please make sure that your codegen config file contains either the "schema" field
        or every generated file has its own "schema" field.

        It should looks like that:
        schema:
          - my-schema.graphql

        or:
        generates:
          path/to/output:
            schema: my-schema.graphql
      ` ) ; } } listr . add ( { title : 'Parse configuration' , task : ( ) => normalize ( ) , } ) ; listr . add ( { title : 'Generate outputs' , task : ( ) => { return new Listr ( Object . keys ( generates ) . map < import ( 'listr' ) . ListrTask > ( filename => { const outputConfig = generates [ filename ] ; const hasPreset = ! ! outputConfig . preset ; return { title : hasPreset ? `Generate to ${ filename } (using EXPERIMENTAL preset "${ outputConfig . preset }")` : `Generate ${ filename }` , task : ( ) => { let outputSchemaAst ; let outputSchema ; const outputFileTemplateConfig = outputConfig . config || { } ; const outputDocuments = [ ] ; const outputSpecificSchemas = normalizeInstanceOrArray < Types . Schema > ( outputConfig . schema ) ; const outputSpecificDocuments = normalizeInstanceOrArray < Types . OperationDocument > ( outputConfig . documents ) ; return new Listr ( [ { title : 'Load GraphQL schemas' , task : wrapTask ( async ( ) => { debugLog ( `[CLI] Loading Schemas` ) ; const schemaPointerMap = { } ; const allSchemaUnnormalizedPointers = [ ... rootSchemas , ... outputSpecificSchemas ] ; for ( const unnormalizedPtr of allSchemaUnnormalizedPointers ) { if ( typeof unnormalizedPtr === 'string' ) { schemaPointerMap [ unnormalizedPtr ] = { } ; } else if ( typeof unnormalizedPtr === 'object' ) { Object . assign ( schemaPointerMap , unnormalizedPtr ) ; } } outputSchemaAst = await context . loadSchema ( schemaPointerMap ) ; outputSchema = getCachedDocumentNodeFromSchema ( outputSchemaAst ) ; } , filename ) , } , { title : 'Load GraphQL documents' , task : wrapTask ( async ( ) => { debugLog ( `[CLI] Loading Documents` ) ; const allDocuments = [ ... rootDocuments , ... outputSpecificDocuments ] ; const documents = await context . loadDocuments ( allDocuments ) ; if ( documents . length > 0 ) { outputDocuments . push ( ... documents ) ; } } , filename ) , } , { title : 'Generate' , task : wrapTask ( async ( ) => { debugLog ( `[CLI] Generating output` ) ; const normalizedPluginsArray = normalizeConfig ( outputConfig . plugins ) ; const pluginLoader = config . pluginLoader || makeDefaultLoader ( context . cwd ) ; const pluginPackages = await Promise . all ( normalizedPluginsArray . map ( plugin => getPluginByName ( Object . keys ( plugin ) [ 0 ] , pluginLoader ) ) ) ; const pluginMap = { } ; const preset = hasPreset ? typeof outputConfig . preset === 'string' ? await getPresetByName ( outputConfig . preset , makeDefaultLoader ( context . cwd ) ) : outputConfig . preset : null ; pluginPackages . forEach ( ( pluginPackage , i ) => { const plugin = normalizedPluginsArray [ i ] ; const name = Object . keys ( plugin ) [ 0 ] ; pluginMap [ name ] = pluginPackage ; } ) ; const mergedConfig = { ... rootConfig , ... ( typeof outputFileTemplateConfig === 'string' ? { value : outputFileTemplateConfig } : outputFileTemplateConfig ) , } ; let outputs = [ ] ; if ( hasPreset ) { outputs = await preset . buildGeneratesSection ( { baseOutputDir : filename , presetConfig : outputConfig . presetConfig || { } , plugins : normalizedPluginsArray , schema : outputSchema , schemaAst : outputSchemaAst , documents : outputDocuments , config : mergedConfig , pluginMap , pluginContext , } ) ; } else { outputs = [ { filename , plugins : normalizedPluginsArray , schema : outputSchema , schemaAst : outputSchemaAst , documents : outputDocuments , config : mergedConfig , pluginMap , pluginContext , } , ] ; } const process = async ( outputArgs ) => { const output = await codegen ( outputArgs ) ; result . push ( { filename : outputArgs . filename , content : output , hooks : outputConfig . hooks || { } , } ) ; } ; await Promise . all ( outputs . map ( process ) ) ; } , filename ) , } , ] , { exitOnError : true , } ) ; } , } ; } ) , { exitOnError : false , concurrent : 4 , } ) ; } , } ) ; await listr . run ( ) ; return result ; }