import * as fs from 'fs' ; import { buildClientSchema , Source , concatAST , parse , DocumentNode , GraphQLSchema , buildASTSchema } from 'graphql' ; import { ToolError } from './errors' ; import { extname , join , normalize , relative } from 'path' ; export function loadSchema ( schemaPath ) { if ( extname ( schemaPath ) === '.json' ) { return loadIntrospectionSchema ( schemaPath ) ; } return loadSDLSchema ( schemaPath ) ; } function loadIntrospectionSchema ( schemaPath ) { if ( ! fs . existsSync ( schemaPath ) ) { throw new ToolError ( `Cannot find GraphQL schema file: ${ schemaPath }` ) ; } const schemaData = require ( schemaPath ) ; if ( ! schemaData . data && ! schemaData . __schema ) { throw new ToolError ( 'GraphQL schema file should contain a valid GraphQL introspection query result' ) ; } return buildClientSchema ( schemaData . data ? schemaData . data : schemaData ) ; } function loadSDLSchema ( schemaPath ) { const authDirectivePath = normalize ( join ( __dirname , '..' , 'awsAppSyncDirectives.graphql' ) ) ; const doc = loadAndMergeQueryDocuments ( [ authDirectivePath , schemaPath ] ) ; return buildASTSchema ( doc ) ; } function extractDocumentFromJavascript ( content , tagName = 'gql' ) { const re = new RegExp ( tagName + '\\s*`([^`/]*)`' , 'g' ) ; let match ; const matches = [ ] ; while ( ( match = re . exec ( content ) ) ) { const doc = match [ 1 ] . replace ( /\${[^}]*}/g , '' ) ; matches . push ( doc ) ; } const doc = matches . join ( '\n' ) ; return doc . length ? doc : null ; } export function loadAndMergeQueryDocuments ( inputPaths , tagName = 'gql' ) { const sources = inputPaths . map ( inputPath => { const body = fs . readFileSync ( inputPath , 'utf8' ) ; if ( ! body ) { return null ; } if ( inputPath . endsWith ( '.jsx' ) || inputPath . endsWith ( '.js' ) || inputPath . endsWith ( '.tsx' ) || inputPath . endsWith ( '.ts' ) ) { const doc = extractDocumentFromJavascript ( body . toString ( ) , tagName ) ; return doc ? new Source ( doc , inputPath ) : null ; } return new Source ( body , inputPath ) ; } ) . filter ( ( source ) : source is Source => Boolean ( source ) ) ; const parsedSources = sources . map ( source => { try { return parse ( source ) ; } catch ( err ) { const relativePathToInput = relative ( process . cwd ( ) , source . name ) ; throw new ToolError ( `Could not parse graphql operations in ${ relativePathToInput }\n  Failed on : ${ source . body }` ) ; } } ) ; return concatAST ( parsedSources ) ; }