UNPKG

amplify-codegen

Version:
168 lines (157 loc) • 6.1 kB
const Ora = require('ora'); const process = require('process'); const { loadConfig } = require('../codegen-config'); const constants = require('../constants'); const generateStatements = require('./statements'); const generateTypes = require('./types'); const { AmplifyCodeGenNoAppSyncAPIAvailableError: NoAppSyncAPIAvailableError, AmplifyCodeGenAPINotFoundError } = require('../errors'); const { downloadIntrospectionSchemaWithProgress, getAppSyncAPIDetails, getAppSyncAPIInfo, getProjectAwsRegion, updateAmplifyMeta, getSDLSchemaLocation, getFrontEndHandler, } = require('../utils'); const addWalkThrough = require('../walkthrough/add'); const changeAppSyncRegion = require('../walkthrough/changeAppSyncRegions'); const path = require('path'); const fs = require('fs-extra'); const askForFrontend = require('../walkthrough/questions/selectFrontend'); const askForFramework = require('../walkthrough/questions/selectFramework'); const frontends = ['android', 'ios', 'javascript']; const frameworks = ['angular', 'ember', 'ionic', 'react', 'react-native', 'vue', 'none']; async function add(context, apiId = null, region = 'us-east-1') { let withoutInit = false; // Determine if working in an amplify project try { await context.amplify.getProjectMeta(); } catch (e) { withoutInit = true; const config = loadConfig(context, withoutInit); if (config.getProjects().length) { throw new Error(constants.ERROR_CODEGEN_SUPPORT_MAX_ONE_API); } } const schemaPath = ['schema.graphql', 'schema.json'].map(p => path.join(process.cwd(), p)).find(p => fs.existsSync(p)); if (withoutInit && !(apiId || schemaPath)) { throw Error( `Provide an AppSync API ID with --apiId or manually download schema.graphql or schema.json and place in ${process.cwd()} before adding codegen when not in an amplify project`, ); } // Grab the frontend let frontend; if (withoutInit) { ({ frontend } = context.parameters.options); if (frontend) { // Make sure provided frontend prarameter is valid if (!frontends.includes(frontend)) { throw Error('Invalid frontend provided'); } } else { frontend = await askForFrontend(frontends); } } // Grab the framework let framework; if (withoutInit) { ({ framework } = context.parameters.options); if (framework) { if (frontend !== 'javascript' || !frameworks.includes(framework)) { throw Error('Invalid framework provided'); } } else if (frontend === 'javascript') { framework = await askForFramework(frameworks); } } if (!withoutInit) { region = getProjectAwsRegion(context); } const config = loadConfig(context, withoutInit); if (config.getProjects().length) { throw new Error(constants.ERROR_CODEGEN_SUPPORT_MAX_ONE_API); } let apiDetails; if (!withoutInit && !apiId) { const availableAppSyncApis = getAppSyncAPIDetails(context); // published and un-published if (availableAppSyncApis.length === 0) { throw new NoAppSyncAPIAvailableError(constants.ERROR_CODEGEN_NO_API_AVAILABLE); } [apiDetails] = availableAppSyncApis; apiDetails.isLocal = true; } else if (apiId) { let shouldRetry = true; while (shouldRetry) { const apiDetailSpinner = new Ora(); try { apiDetailSpinner.start('Getting API details'); apiDetails = await getAppSyncAPIInfo(context, apiId, region); if (!withoutInit) { await updateAmplifyMeta(context, apiDetails); } apiDetailSpinner.succeed(); break; } catch (e) { apiDetailSpinner.fail(); if (e instanceof AmplifyCodeGenAPINotFoundError) { context.print.info(`AppSync API was not found in region ${region}`); ({ shouldRetry, region } = await changeAppSyncRegion(context, region)); } else { throw e; } } } } // else no appsync API, but has schema.graphql or schema.json if (!withoutInit && !apiDetails) { return; } const answer = await addWalkThrough(context, undefined, withoutInit, frontend, framework); let schema; if (!withoutInit) { if (!apiDetails.isLocal) { schema = await downloadIntrospectionSchemaWithProgress(context, apiDetails.id, answer.schemaLocation, region); } else if (getFrontEndHandler(context) === 'android') { schema = answer.schemaLocation; } else { schema = getSDLSchemaLocation(apiDetails.name); } } else if (apiDetails) { schema = await downloadIntrospectionSchemaWithProgress(context, apiDetails.id, path.join(process.cwd(), 'schema.json'), region); } else { schema = schemaPath; } const newProject = { projectName: withoutInit ? 'Codegen Project' : apiDetails.name, includes: answer.includePattern, excludes: [...answer.excludePattern, answer.generatedFileName]?.filter(item => item), // Set schema path to use posix separators. Node can handle windows and posix separators regradless of platform // Ensures all paths in .graphlqconfig.yml use posix style // Fallback to \ because path.win32 is not implemented by path-browserify schema: schema.split(path.win32?.sep || '\\').join(path.posix.sep), amplifyExtension: { codeGenTarget: answer.target || '', generatedFileName: answer.generatedFileName || '', docsFilePath: answer.docsFilePath, region, apiId, ...(withoutInit ? { frontend } : {}), ...(withoutInit && frontend === 'javascript' ? { framework } : {}), // The default Amplify JS lib version is set for 6 for angular codegen ...(answer.target === 'angular' ? { amplifyJsLibraryVersion: 6 } : {}), }, }; if (answer.maxDepth) { newProject.amplifyExtension.maxDepth = answer.maxDepth; } config.addProject(newProject); if (answer.shouldGenerateDocs) { await generateStatements(context, false, undefined, withoutInit, frontend); } if (answer.shouldGenerateCode) { await generateTypes(context, false, withoutInit, frontend); } config.save(); } module.exports = add;